diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 7273b6a50..000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,3 +0,0 @@ -@altavir - -/kmath-trajectory @ESchouten \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6ad294e18..f39e12a12 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,24 +1,37 @@ name: Gradle build -on: - push: - branches: [ dev, master ] - pull_request: +on: [ push ] jobs: build: - runs-on: windows-latest - timeout-minutes: 20 + strategy: + matrix: + os: [ macOS-latest, windows-latest ] + runs-on: ${{matrix.os}} + timeout-minutes: 30 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3.5.1 + - name: Checkout the repo + uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1 with: - java-version: '11' - distribution: 'liberica' - cache: 'gradle' - - name: Gradle Wrapper Validation - uses: gradle/wrapper-validation-action@v1.0.4 - - name: Gradle Build - uses: gradle/gradle-build-action@v2.4.2 + java-version: 11 + - name: Add msys to path + if: matrix.os == 'windows-latest' + run: SETX PATH "%PATH%;C:\msys64\mingw64\bin" + - name: Cache gradle + uses: actions/cache@v2 with: - arguments: test jvmTest + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache konan + uses: actions/cache@v2 + with: + path: ~/.konan + key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Build + run: ./gradlew build --no-daemon --stacktrace diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index ba1f5d1e3..110537a10 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,31 +1,26 @@ name: Dokka publication on: - workflow_dispatch: - release: - types: [ created ] + push: + branches: + - master jobs: build: runs-on: ubuntu-20.04 - timeout-minutes: 40 steps: - - uses: actions/checkout@v3.0.0 - - uses: actions/setup-java@v3.0.0 + - name: Checkout the repo + uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1 with: java-version: 11 - distribution: liberica - - name: Cache konan - uses: actions/cache@v3.0.1 - with: - path: ~/.konan - key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} - restore-keys: | - ${{ runner.os }}-gradle- - - uses: gradle/gradle-build-action@v2.4.2 - with: - arguments: dokkaHtmlMultiModule --no-parallel - - uses: JamesIves/github-pages-deploy-action@v4.3.0 + - name: Build + run: | + ./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace + mv build/dokka/htmlMultiModule/-modules.html build/dokka/htmlMultiModule/index.html + - name: Deploy to GitHub Pages + uses: JamesIves/github-pages-deploy-action@4.1.0 with: branch: gh-pages folder: build/dokka/htmlMultiModule diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 31d539cdd..ca374574e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,7 +3,8 @@ name: Gradle publish on: workflow_dispatch: release: - types: [ created ] + types: + - created jobs: publish: @@ -14,13 +15,24 @@ jobs: os: [ macOS-latest, windows-latest ] runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v3.0.0 - - uses: actions/setup-java@v3.10.0 + - name: Checkout the repo + uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1 with: java-version: 11 - distribution: liberica + - name: Add msys to path + if: matrix.os == 'windows-latest' + run: SETX PATH "%PATH%;C:\msys64\mingw64\bin" + - name: Cache gradle + uses: actions/cache@v2 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} + restore-keys: | + ${{ runner.os }}-gradle- - name: Cache konan - uses: actions/cache@v3.0.1 + uses: actions/cache@v2 with: path: ~/.konan key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} @@ -28,23 +40,20 @@ jobs: ${{ runner.os }}-gradle- - name: Publish Windows Artifacts if: matrix.os == 'windows-latest' - uses: gradle/gradle-build-action@v2.4.2 - with: - arguments: | - publishAllPublicationsToSpaceRepository - -Ppublishing.targets=all - -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} - -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} + run: > + ./gradlew release --no-daemon + -Ppublishing.enabled=true + -Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }} + -Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }} + -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }} + -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }} - name: Publish Mac Artifacts if: matrix.os == 'macOS-latest' - uses: gradle/gradle-build-action@v2.4.2 - with: - arguments: | - publishMacosX64PublicationToSpaceRepository - publishMacosArm64PublicationToSpaceRepository - publishIosX64PublicationToSpaceRepository - publishIosArm64PublicationToSpaceRepository - publishIosSimulatorArm64PublicationToSpaceRepository - -Ppublishing.targets=all - -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} - -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} + run: > + ./gradlew release --no-daemon + -Ppublishing.enabled=true + -Ppublishing.platform=macosX64 + -Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }} + -Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }} + -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }} + -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }} diff --git a/.gitignore b/.gitignore index 96a556ae1..2a13b9e3c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,10 @@ build/ out/ .idea/ -.vscode/ -.fleet/ +!.idea/copyright/ + +.vscode/ # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar @@ -16,8 +17,3 @@ out/ # Generated by javac -h and runtime *.class *.log - -!/.idea/copyright/ -!/.idea/scopes/ -/gradle/yarn.lock - diff --git a/.idea/copyright/kmath.xml b/.idea/copyright/kmath.xml index 840e0c87c..6fe438777 100644 --- a/.idea/copyright/kmath.xml +++ b/.idea/copyright/kmath.xml @@ -1,7 +1,6 @@ - \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml index 1c10bd6f5..6cc25cb4a 100644 --- a/.idea/copyright/profiles_settings.xml +++ b/.idea/copyright/profiles_settings.xml @@ -1,21 +1,7 @@ - + - + - - - - - - - - \ No newline at end of file diff --git a/.idea/scopes/Apply_copyright.xml b/.idea/scopes/Apply_copyright.xml deleted file mode 100644 index a2575f774..000000000 --- a/.idea/scopes/Apply_copyright.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.space.kts b/.space.kts index ce52a2f5c..d70ad6d59 100644 --- a/.space.kts +++ b/.space.kts @@ -1,48 +1,3 @@ -import kotlin.io.path.readText - -val projectName = "kmath" - job("Build") { - //Perform only jvm tests - gradlew("spc.registry.jetbrains.space/p/sci/containers/kotlin-ci:1.0.3", "test", "jvmTest") + gradlew("openjdk:11", "build") } - -job("Publish") { - startOn { - gitPush { enabled = false } - } - container("spc.registry.jetbrains.space/p/sci/containers/kotlin-ci:1.0.3") { - env["SPACE_USER"] = "{{ project:space_user }}" - env["SPACE_TOKEN"] = "{{ project:space_token }}" - kotlinScript { api -> - - val spaceUser = System.getenv("SPACE_USER") - val spaceToken = System.getenv("SPACE_TOKEN") - - // write the version to the build directory - api.gradlew("version") - - //read the version from build file - val version = java.nio.file.Path.of("build/project-version.txt").readText() - - val revisionSuffix = if (version.endsWith("SNAPSHOT")) { - "-" + api.gitRevision().take(7) - } else { - "" - } - - api.space().projects.automation.deployments.start( - project = api.projectIdentifier(), - targetIdentifier = TargetIdentifier.Key(projectName), - version = version+revisionSuffix, - // automatically update deployment status based on the status of a job - syncWithAutomationJob = true - ) - api.gradlew( - "publishAllPublicationsToSpaceRepository", - "-Ppublishing.space.user=\"$spaceUser\"", - "-Ppublishing.space.token=\"$spaceToken\"", - ) - } - } -} \ No newline at end of file diff --git a/.space/CODEOWNERS b/.space/CODEOWNERS deleted file mode 100644 index e69de29bb..000000000 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f011881f..c3bd2641a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,123 +1,42 @@ # KMath -## Unreleased - +## [Unreleased] ### Added - -### Changed - -### Deprecated - -### Removed - -### Fixed - -### Security - -## 0.3.1 - 2023-04-09 - -### Added -- Wasm support for `memory`, `core`, `complex` and `functions` modules. -- Generic builders for `BufferND` and `MutableBufferND` -- `NamedMatrix` - matrix with symbol-based indexing -- `Expression` with default arguments -- Type-aliases for numbers like `Float64` -- Autodiff for generic algebra elements in core! -- Algebra now has an obligatory `bufferFactory` (#477). - -### Changed -- Geometry uses type-safe angles -- Tensor operations switched to prefix notation -- Row-wise and column-wise ND shapes in the core -- Shape is read-only -- Major refactor of tensors (only minor API changes) -- Kotlin 1.8.20 -- `LazyStructure` `deffered` -> `async` to comply with coroutines code style -- Default `dot` operation in tensor algebra no longer support broadcasting. Instead `matmul` operation is added to `DoubleTensorAlgebra`. -- Multik went MPP - -### Removed -- Trajectory moved to https://github.com/SciProgCentre/maps-kt -- Polynomials moved to https://github.com/SciProgCentre/kmath-polynomial - -## 0.3.0 - -### Added -- `ScaleOperations` interface -- `Field` extends `ScaleOperations` +- ScaleOperations interface +- Field extends ScaleOperations - Basic integration API - Basic MPP distributions and samplers -- `bindSymbolOrNull` +- bindSymbolOrNull - Blocking chains and Statistics - Multiplatform integration - Integration for any Field element -- Extended operations for ND4J fields -- Jupyter Notebook integration module (kmath-jupyter) -- `@PerformancePitfall` annotation to mark possibly slow API -- Unified architecture for Integration and Optimization using features. -- `BigInt` operation performance improvement and fixes by @zhelenskiy (#328) -- Integration between `MST` and Symja `IExpr` -- Complex power -- Separate methods for UInt, Int and Number powers. NaN safety. -- Tensorflow prototype -- `ValueAndErrorField` -- MST compilation to WASM: #286 -- Jafama integration: #176 -- `contentEquals` with tolerance: #364 -- Compilation to TeX for MST: #254 ### Changed -- Annotations moved to `space.kscience.kmath` - Exponential operations merged with hyperbolic functions - Space is replaced by Group. Space is reserved for vector spaces. - VectorSpace is now a vector space - Buffer factories for primitives moved to MutableBuffer.Companion -- Rename `NDStructure` and `NDAlgebra` to `StructureND` and `AlgebraND` respectively -- `Real` -> `Double` +- NDStructure and NDAlgebra to StructureND and AlgebraND respectively +- Real -> Double - DataSets are moved from functions to core - Redesign advanced Chain API -- Redesign `MST`. Remove `MstExpression`. -- Move `MST` to core -- Separated benchmarks and examples -- Rewrite `kmath-ejml` without `ejml-simple` artifact, support sparse matrices -- Promote stability of kmath-ast and kmath-kotlingrad to EXPERIMENTAL. -- ColumnarData returns nullable column -- `MST` is made sealed interface -- Replace `MST.Symbolic` by `Symbol`, `Symbol` now implements MST -- Remove Any restriction on polynomials -- Add `out` variance to type parameters of `StructureND` and its implementations where possible -- Rename `DifferentiableMstExpression` to `KotlingradExpression` -- `FeatureSet` now accepts only `Feature`. It is possible to override keys and use interfaces. -- Use `Symbol` factory function instead of `StringSymbol` -- New discoverability pattern: `.algebra.` -- Adjusted commons-math API for linear solvers to match conventions. -- Buffer algebra does not require size anymore -- Operations -> Ops -- Default Buffer and ND algebras are now Ops and lack neutral elements (0, 1) as well as algebra-level shapes. -- Tensor algebra takes read-only structures as input and inherits AlgebraND -- `UnivariateDistribution` renamed to `Distribution1D` -- Rework of histograms. -- `UnivariateFunction` -> `Function1D`, `MultivariateFunction` -> `FunctionND` +- Redesign MST. Remove MSTExpression. +- Move MST to core ### Deprecated -- Specialized `DoubleBufferAlgebra` ### Removed - Nearest in Domain. To be implemented in geometry package. - Number multiplication and division in main Algebra chain - `contentEquals` from Buffer. It moved to the companion. - MSTExpression -- Expression algebra builders -- Complex and Quaternion no longer are elements. -- Second generic from DifferentiableExpression -- Algebra elements are completely removed. Use algebra contexts instead. ### Fixed - Ring inherits RingOperations, not GroupOperations -- Univariate histogram filling -## 0.2.0 +### Security +## [0.2.0] ### Added - `fun` annotation for SAM interfaces in library - Explicit `public` visibility for all public APIs @@ -161,6 +80,8 @@ - `symbol` method in `Algebra` renamed to `bindSymbol` to avoid ambiguity - Add `out` projection to `Buffer` generic +### Deprecated + ### Removed - `kmath-koma` module because it doesn't support Kotlin 1.4. - Support of `legacy` JS backend (we will support only IR) @@ -172,7 +93,9 @@ ### Fixed - `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140) -## 0.1.4 +### Security + +## [0.1.4] ### Added - Functional Expressions API diff --git a/README.md b/README.md index 7c1f759c1..0210b4caf 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ [![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) -![Gradle build](https://github.com/SciProgCentre/kmath/workflows/Gradle%20build/badge.svg) +![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) -[![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/spc/p/sci/maven/space/kscience/) +[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) # KMath -Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based -analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior -architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like -experience could be achieved with [kmath-for-real](/kmath-for-real) extension module. +Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to +Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture +designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could +be achieved with [kmath-for-real](/kmath-for-real) extension module. -[Documentation site (**WIP**)](https://SciProgCentre.github.io/kmath/) +[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) ## Publications and talks @@ -21,76 +21,100 @@ experience could be achieved with [kmath-for-real](/kmath-for-real) extension mo # Goal -* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native) - . +* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native). * Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide bindings and wrappers with those abstractions for popular optimized platform libraries. ## Non-goals -* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API. +* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API. * Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. -* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like - for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better - experience for those, who want to work with specific types. +* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like +for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better +experience for those, who want to work with specific types. ## Features and stability -KMath is a modular library. Different modules provide different features with different API stability guarantees. All -core modules are released with the same version, but with different API change policy. The features are described in -module definitions below. The module stability could have the following levels: +KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels: -* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could - break any moment. You can still use it, but be sure to fix the specific version. -* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked - with `@UnstableKMathAPI` or other stability warning annotations. -* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor - versions, but not in patch versions. API is protected - with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. +* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. +* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations. +* **DEVELOPMENT**. API breaking genrally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## Modules +
-### [benchmarks](benchmarks) +* ### [examples](examples) > > > **Maturity**: EXPERIMENTAL +
-### [examples](examples) +* ### [kmath-ast](kmath-ast) > > -> **Maturity**: EXPERIMENTAL - -### [kmath-ast](kmath-ast) -> -> -> **Maturity**: EXPERIMENTAL +> **Maturity**: PROTOTYPE > > **Features:** -> - [expression-language](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser +> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser +> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation +> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure +> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter > - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler > - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler -> - [rendering](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering +
-### [kmath-commons](kmath-commons) +* ### [kmath-commons](kmath-commons) > > > **Maturity**: EXPERIMENTAL +
-### [kmath-complex](kmath-complex) +* ### [kmath-complex](kmath-complex) > Complex numbers and quaternions. > > **Maturity**: PROTOTYPE > > **Features:** -> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex numbers operations -> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions and their composition +> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers +> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions +
-### [kmath-core](kmath-core) +* ### [kmath-core](kmath-core) > Core classes, algebra definitions, basic linear algebra > > **Maturity**: DEVELOPMENT @@ -104,32 +128,36 @@ module definitions below. The module stability could have the following levels: objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high performance calculations to code generation. > - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains -> - [autodiff](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation +> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation +
-### [kmath-coroutines](kmath-coroutines) +* ### [kmath-coroutines](kmath-coroutines) > > > **Maturity**: EXPERIMENTAL +
-### [kmath-dimensions](kmath-dimensions) +* ### [kmath-dimensions](kmath-dimensions) > > > **Maturity**: PROTOTYPE +
-### [kmath-ejml](kmath-ejml) +* ### [kmath-ejml](kmath-ejml) > > > **Maturity**: PROTOTYPE > > **Features:** -> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : Point implementations. -> - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : Matrix implementation. -> - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : LinearSpace implementations. +> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : The Point implementation using SimpleMatrix. +> - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : The Matrix implementation using SimpleMatrix. +> - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : The LinearSpace implementation using SimpleMatrix. +
-### [kmath-for-real](kmath-for-real) -> Extension module that should be used to achieve numpy-like behavior. +* ### [kmath-for-real](kmath-for-real) +> Extension module that should be used to achieve numpy-like behavior. All operations are specialized to work with `Double` numbers without declaring algebraic contexts. One can still use generic algebras though. > @@ -140,9 +168,10 @@ One can still use generic algebras though. > - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures > - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators +
-### [kmath-functions](kmath-functions) -> +* ### [kmath-functions](kmath-functions) +> Functions, integration and interpolation > > **Maturity**: EXPERIMENTAL > @@ -153,53 +182,34 @@ One can still use generic algebras though. > - [spline interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator. > - [integration](kmath-functions/#) : Univariate and multivariate quadratures +
-### [kmath-geometry](kmath-geometry) +* ### [kmath-geometry](kmath-geometry) > > > **Maturity**: PROTOTYPE +
-### [kmath-histograms](kmath-histograms) +* ### [kmath-histograms](kmath-histograms) > > > **Maturity**: PROTOTYPE +
-### [kmath-jafama](kmath-jafama) +* ### [kmath-kotlingrad](kmath-kotlingrad) > > > **Maturity**: PROTOTYPE -> -> **Features:** -> - [jafama-double](kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama +
- -### [kmath-jupyter](kmath-jupyter) -> -> -> **Maturity**: PROTOTYPE - -### [kmath-kotlingrad](kmath-kotlingrad) -> -> -> **Maturity**: EXPERIMENTAL -> -> **Features:** -> - [differentiable-mst-expression](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression. -> - [scalars-adapters](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST - - -### [kmath-memory](kmath-memory) -> An API and basic implementation for arranging objects in a continuous memory block. +* ### [kmath-memory](kmath-memory) +> An API and basic implementation for arranging objects in a continous memory block. > > **Maturity**: DEVELOPMENT +
-### [kmath-multik](kmath-multik) -> -> -> **Maturity**: PROTOTYPE - -### [kmath-nd4j](kmath-nd4j) -> +* ### [kmath-nd4j](kmath-nd4j) +> ND4J NDStructure implementation and according NDAlgebra classes > > **Maturity**: EXPERIMENTAL > @@ -208,77 +218,47 @@ One can still use generic algebras though. > - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long > - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double +
-### [kmath-optimization](kmath-optimization) +* ### [kmath-stat](kmath-stat) > > > **Maturity**: EXPERIMENTAL +
-### [kmath-stat](kmath-stat) -> -> -> **Maturity**: EXPERIMENTAL - -### [kmath-symja](kmath-symja) -> -> -> **Maturity**: PROTOTYPE - -### [kmath-tensorflow](kmath-tensorflow) -> -> -> **Maturity**: PROTOTYPE - -### [kmath-tensors](kmath-tensors) -> -> -> **Maturity**: PROTOTYPE -> -> **Features:** -> - [tensor algebra](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) -> - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. -> - [linear algebra operations](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. - - -### [kmath-viktor](kmath-viktor) +* ### [kmath-viktor](kmath-viktor) > > > **Maturity**: DEVELOPMENT - -### [test-utils](test-utils) -> -> -> **Maturity**: EXPERIMENTAL +
## Multi-platform support -KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the -[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features -are delegated to platform-specific implementations even if they could be provided in the common module for performance -reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and +KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the +[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features +are delegated to platform-specific implementations even if they could be provided in the common module for performance +reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and feedback are also welcome. ## Performance -Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both -performance and flexibility. +Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve +both performance and flexibility. -We expect to focus on creating convenient universal API first and then work on increasing performance for specific -cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized -native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. +We expect to focus on creating convenient universal API first and then work on increasing performance for specific +cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized +native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be +better than SciPy. ## Requirements -KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for -execution to get better performance. +KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance. ### Repositories -Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) -repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of -[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could -be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: +Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of +[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: ```kotlin repositories { @@ -286,8 +266,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:$version") - // api("space.kscience:kmath-core-jvm:$version") for jvm-specific version + api("space.kscience:kmath-core:0.3.0-dev-6") + // api("space.kscience:kmath-core-jvm:0.3.0-dev-6") for jvm-specific version } ``` @@ -295,6 +275,7 @@ Gradle `6.0+` is required for multiplatform artifacts. ## Contributing -The project requires a lot of additional work. The most important thing we need is a feedback about what features are -required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues -marked with [waiting for a hero](https://github.com/SciProgCentre/kmath/labels/waiting%20for%20a%20hero) label. \ No newline at end of file +The project requires a lot of additional work. The most important thing we need is a feedback about what features are +required the most. Feel free to create feature requests. We are also welcome to code contributions, +especially in issues marked with +[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. diff --git a/benchmarks/README.md b/benchmarks/README.md deleted file mode 100644 index cd8fbafd3..000000000 --- a/benchmarks/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Module benchmarks - - - diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts deleted file mode 100644 index 24471a9e4..000000000 --- a/benchmarks/build.gradle.kts +++ /dev/null @@ -1,174 +0,0 @@ -@file:Suppress("UNUSED_VARIABLE") - -import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile -import space.kscience.kmath.benchmarks.addBenchmarkProperties - -plugins { - kotlin("multiplatform") - alias(spclibs.plugins.kotlin.plugin.allopen) - id("org.jetbrains.kotlinx.benchmark") -} - -allOpen.annotation("org.openjdk.jmh.annotations.State") -sourceSets.register("benchmarks") - -repositories { - mavenCentral() -} - -val multikVersion: String by rootProject.extra - -kotlin { - jvm() - - js(IR) { - nodejs() - } - - sourceSets { - all { - languageSettings { - progressiveMode = true - optIn("kotlin.contracts.ExperimentalContracts") - optIn("kotlin.ExperimentalUnsignedTypes") - optIn("space.kscience.kmath.UnstableKMathAPI") - } - } - - val commonMain by getting { - dependencies { - implementation(project(":kmath-ast")) - implementation(project(":kmath-core")) - implementation(project(":kmath-coroutines")) - implementation(project(":kmath-complex")) - implementation(project(":kmath-stat")) - implementation(project(":kmath-dimensions")) - implementation(project(":kmath-for-real")) - implementation(project(":kmath-tensors")) - implementation(project(":kmath-multik")) - implementation("org.jetbrains.kotlinx:multik-default:$multikVersion") - implementation(spclibs.kotlinx.benchmark.runtime) - } - } - - val jvmMain by getting { - dependencies { - implementation(project(":kmath-commons")) - implementation(project(":kmath-ejml")) - implementation(project(":kmath-nd4j")) - implementation(project(":kmath-kotlingrad")) - implementation(project(":kmath-viktor")) - implementation(project(":kmath-jafama")) - implementation(projects.kmath.kmathTensorflow) - implementation("org.tensorflow:tensorflow-core-platform:0.4.0") - implementation("org.nd4j:nd4j-native:1.0.0-M1") - // uncomment if your system supports AVX2 - // val os = System.getProperty("os.name") - // - // if (System.getProperty("os.arch") in arrayOf("x86_64", "amd64")) when { - // os.startsWith("Windows") -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:windows-x86_64-avx2") - // os == "Linux" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:linux-x86_64-avx2") - // os == "Mac OS X" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:macosx-x86_64-avx2") - // } else - // implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - } - } - } -} - -// Configure benchmark -benchmark { - // Setup configurations - targets { - register("jvm") - register("js") - } - - fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() { - warmups = 2 - iterations = 5 - iterationTime = 2000 - iterationTimeUnit = "ms" - } - - configurations.register("buffer") { - commonConfiguration() - include("BufferBenchmark") - } - - configurations.register("nd") { - commonConfiguration() - include("NDFieldBenchmark") - } - - configurations.register("dot") { - commonConfiguration() - include("DotBenchmark") - } - - configurations.register("expressions") { - // Some extra precision - warmups = 2 - iterations = 10 - iterationTime = 10 - iterationTimeUnit = "s" - outputTimeUnit = "s" - include("ExpressionsInterpretersBenchmark") - } - - configurations.register("matrixInverse") { - commonConfiguration() - include("MatrixInverseBenchmark") - } - - configurations.register("bigInt") { - commonConfiguration() - include("BigIntBenchmark") - } - - configurations.register("jafamaDouble") { - commonConfiguration() - include("JafamaBenchmark") - } - - configurations.register("tensorAlgebra") { - commonConfiguration() - include("TensorAlgebraBenchmark") - } - - configurations.register("viktor") { - commonConfiguration() - include("ViktorBenchmark") - } - - configurations.register("viktorLog") { - commonConfiguration() - include("ViktorLogBenchmark") - } - - configurations.register("integration") { - commonConfiguration() - include("IntegrationBenchmark") - } -} - -kotlin.sourceSets.all { - with(languageSettings) { - optIn("kotlin.contracts.ExperimentalContracts") - optIn("kotlin.ExperimentalUnsignedTypes") - optIn("space.kscience.kmath.UnstableKMathAPI") - } -} - -tasks.withType { - kotlinOptions { - jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xlambdas=indy" - } -} - -readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL -} - -addBenchmarkProperties() diff --git a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt deleted file mode 100644 index cb07e489a..000000000 --- a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.bindSymbol -import space.kscience.kmath.operations.invoke -import kotlin.math.sin -import kotlin.random.Random -import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression -import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression - -@State(Scope.Benchmark) -class ExpressionsInterpretersBenchmark { - /** - * Benchmark case for [Expression] created with [expressionInExtendedField]. - */ - @Benchmark - fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, blackhole) - - /** - * Benchmark case for [Expression] created with [toExpression]. - */ - @Benchmark - fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, blackhole) - - /** - * Benchmark case for [Expression] created with [compileToExpression]. - */ - @Benchmark - fun wasmExpression(blackhole: Blackhole) = invokeAndSum(wasm, blackhole) - - /** - * Benchmark case for [Expression] created with [compileToExpression]. - */ - @Benchmark - fun estreeExpression(blackhole: Blackhole) = invokeAndSum(estree, blackhole) - - /** - * Benchmark case for [Expression] implemented manually with `kotlin.math` functions. - */ - @Benchmark - fun rawExpression(blackhole: Blackhole) = invokeAndSum(raw, blackhole) - - /** - * Benchmark case for direct computation w/o [Expression]. - */ - @Benchmark - fun justCalculate(blackhole: Blackhole) { - val random = Random(0) - var sum = 0.0 - - repeat(times) { - val x = random.nextDouble() - sum += x * 2.0 + 2.0 / x - 16.0 / sin(x) - } - - blackhole.consume(sum) - } - - private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { - val random = Random(0) - var sum = 0.0 - val m = HashMap() - - repeat(times) { - m[x] = random.nextDouble() - sum += expr(m) - } - - blackhole.consume(sum) - } - - private companion object { - private val x by symbol - private const val times = 1_000_000 - - private val functional = DoubleField.expression { - val x = bindSymbol(Symbol.x) - x * number(2.0) + 2.0 / x - 16.0 / sin(x) - } - - private val node = MstExtendedField { - x * 2.0 + number(2.0) / x - number(16.0) / sin(x) - } - - private val mst = node.toExpression(DoubleField) - @OptIn(UnstableKMathAPI::class) - private val wasm = node.wasmCompileToExpression(DoubleField) - private val estree = node.estreeCompileToExpression(DoubleField) - - private val raw = Expression { args -> - val x = args[x]!! - x * 2.0 + 2.0 / x - 16.0 / sin(x) - } - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt deleted file mode 100644 index d07b7b4df..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - - -import kotlinx.benchmark.Blackhole -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.BigIntField -import space.kscience.kmath.operations.JBigIntegerField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.parseBigInteger -import java.math.BigInteger - - -@UnstableKMathAPI -@State(Scope.Benchmark) -internal class BigIntBenchmark { - - val kmSmallNumber = BigIntField.number(100) - val jvmSmallNumber = JBigIntegerField.number(100) - val kmNumber = BigIntField.number(Int.MAX_VALUE) - val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE) - val kmLargeNumber = BigIntField { number(11).pow(100_000U) } - val jvmLargeNumber: BigInteger = JBigIntegerField { number(11).pow(100_000) } - val bigExponent = 50_000 - - @Benchmark - fun kmSmallAdd(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmSmallNumber + kmSmallNumber + kmSmallNumber) - } - - @Benchmark - fun jvmSmallAdd(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmSmallNumber + jvmSmallNumber + jvmSmallNumber) - } - - @Benchmark - fun kmAdd(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmNumber + kmNumber + kmNumber) - } - - @Benchmark - fun jvmAdd(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmNumber + jvmNumber + jvmNumber) - } - - @Benchmark - fun kmAddLarge(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmLargeNumber + kmLargeNumber + kmLargeNumber) - } - - @Benchmark - fun jvmAddLarge(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmLargeNumber + jvmLargeNumber + jvmLargeNumber) - } - - @Benchmark - fun kmMultiply(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmNumber * kmNumber * kmNumber) - } - - @Benchmark - fun kmMultiplyLarge(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmLargeNumber*kmLargeNumber) - } - - @Benchmark - fun jvmMultiply(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmNumber * jvmNumber * jvmNumber) - } - - @Benchmark - fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmLargeNumber*jvmLargeNumber) - } - - @Benchmark - fun kmPower(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmNumber.pow(bigExponent.toUInt())) - } - - @Benchmark - fun jvmPower(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmNumber.pow(bigExponent)) - } - - @Benchmark - fun kmParsing16(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume("0x7f57ed8b89c29a3b9a85c7a5b84ca3929c7b7488593".parseBigInteger()) - } - - @Benchmark - fun kmParsing10(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume("236656783929183747565738292847574838922010".parseBigInteger()) - } - - @Benchmark - fun jvmParsing10(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume("236656783929183747565738292847574838922010".toBigInteger(10)) - } - - @Benchmark - fun jvmParsing16(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume("7f57ed8b89c29a3b9a85c7a5b84ca3929c7b7488593".toBigInteger(16)) - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt deleted file mode 100644 index c2616303b..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.ComplexField -import space.kscience.kmath.complex.complex -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.getDouble -import space.kscience.kmath.structures.permute - -@State(Scope.Benchmark) -internal class BufferBenchmark { - - @Benchmark - fun doubleArrayReadWrite(blackhole: Blackhole) { - val buffer = DoubleArray(size) { it.toDouble() } - var res = 0.0 - (0 until size).forEach { - res += buffer[it] - } - blackhole.consume(res) - } - - @Benchmark - fun doubleBufferReadWrite(blackhole: Blackhole) { - val buffer = DoubleBuffer(size) { it.toDouble() } - var res = 0.0 - (0 until size).forEach { - res += buffer[it] - } - blackhole.consume(res) - } - - @Benchmark - fun bufferViewReadWrite(blackhole: Blackhole) { - val buffer = DoubleBuffer(size) { it.toDouble() }.permute(reversedIndices) - var res = 0.0 - (0 until size).forEach { - res += buffer[it] - } - blackhole.consume(res) - } - - @Benchmark - fun bufferViewReadWriteSpecialized(blackhole: Blackhole) { - val buffer = DoubleBuffer(size) { it.toDouble() }.permute(reversedIndices) - var res = 0.0 - (0 until size).forEach { - res += buffer.getDouble(it) - } - blackhole.consume(res) - } - - @Benchmark - fun complexBufferReadWrite(blackhole: Blackhole) = ComplexField { - val buffer = Buffer.complex(size / 2) { Complex(it.toDouble(), -it.toDouble()) } - - var res = zero - (0 until size / 2).forEach { - res += buffer[it] - } - - blackhole.consume(res) - } - - private companion object { - private const val size = 100 - private val reversedIndices = IntArray(size){it}.apply { reverse() } - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt deleted file mode 100644 index 7cbe83113..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.commons.linear.CMLinearSpace -import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM -import space.kscience.kmath.linear.invoke -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensorflow.produceWithTF -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.tensorAlgebra -import kotlin.random.Random - -@State(Scope.Benchmark) -internal class DotBenchmark { - companion object { - val random = Random(12224) - const val dim = 1000 - - //creating invertible matrix - val matrix1 = DoubleField.linearSpace.buildMatrix(dim, dim) { _, _ -> - random.nextDouble() - } - val matrix2 = DoubleField.linearSpace.buildMatrix(dim, dim) { _, _ -> - random.nextDouble() - } - - val cmMatrix1 = CMLinearSpace { matrix1.toCM() } - val cmMatrix2 = CMLinearSpace { matrix2.toCM() } - - val ejmlMatrix1 = EjmlLinearSpaceDDRM { matrix1.toEjml() } - val ejmlMatrix2 = EjmlLinearSpaceDDRM { matrix2.toEjml() } - } - - - @Benchmark - fun tfDot(blackhole: Blackhole) { - blackhole.consume( - DoubleField.produceWithTF { - matrix1 dot matrix1 - } - ) - } - - @Benchmark - fun cmDotWithConversion(blackhole: Blackhole) = CMLinearSpace { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun cmDot(blackhole: Blackhole) = CMLinearSpace { - blackhole.consume(cmMatrix1 dot cmMatrix2) - } - - @Benchmark - fun ejmlDot(blackhole: Blackhole) = EjmlLinearSpaceDDRM { - blackhole.consume(ejmlMatrix1 dot ejmlMatrix2) - } - - @Benchmark - fun ejmlDotWithConversion(blackhole: Blackhole) = EjmlLinearSpaceDDRM { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun tensorDot(blackhole: Blackhole) = with(DoubleField.tensorAlgebra) { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun multikDot(blackhole: Blackhole) = with(multikAlgebra) { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace) { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun doubleDot(blackhole: Blackhole) = with(DoubleField.linearSpace) { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun doubleTensorDot(blackhole: Blackhole) = DoubleTensorAlgebra.invoke { - blackhole.consume(matrix1 dot matrix2) - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt deleted file mode 100644 index 4df5f372f..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.bindSymbol -import space.kscience.kmath.operations.invoke -import kotlin.math.sin -import kotlin.random.Random - -@State(Scope.Benchmark) -internal class ExpressionsInterpretersBenchmark { - /** - * Benchmark case for [Expression] created with [expressionInExtendedField]. - */ - @Benchmark - fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, blackhole) - - /** - * Benchmark case for [Expression] created with [toExpression]. - */ - @Benchmark - fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, blackhole) - - /** - * Benchmark case for [Expression] created with [compileToExpression]. - */ - @Benchmark - fun asmGenericExpression(blackhole: Blackhole) = invokeAndSum(asmGeneric, blackhole) - - /** - * Benchmark case for [Expression] created with [compileToExpression]. - */ - @Benchmark - fun asmPrimitiveExpressionArray(blackhole: Blackhole) { - val random = Random(0) - var sum = 0.0 - val m = DoubleArray(1) - - repeat(times) { - m[xIdx] = random.nextDouble() - sum += asmPrimitive(m) - } - - blackhole.consume(sum) - } - - /** - * Benchmark case for [Expression] created with [compileToExpression]. - */ - @Benchmark - fun asmPrimitiveExpression(blackhole: Blackhole) = invokeAndSum(asmPrimitive, blackhole) - - /** - * Benchmark case for [Expression] implemented manually with `kotlin.math` functions. - */ - @Benchmark - fun rawExpression(blackhole: Blackhole) = invokeAndSum(raw, blackhole) - - /** - * Benchmark case for direct computation w/o [Expression]. - */ - @Benchmark - fun justCalculate(blackhole: Blackhole) { - val random = Random(0) - var sum = 0.0 - - repeat(times) { - val x = random.nextDouble() - sum += x * 2.0 + 2.0 / x - 16.0 / sin(x) - } - - blackhole.consume(sum) - } - - private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { - val random = Random(0) - var sum = 0.0 - val m = HashMap() - - repeat(times) { - m[x] = random.nextDouble() - sum += expr(m) - } - - blackhole.consume(sum) - } - - private companion object { - private val x by symbol - private const val times = 1_000_000 - - private val functional = DoubleField.expression { - val x = bindSymbol(Symbol.x) - x * number(2.0) + 2.0 / x - 16.0 / sin(x) - } - - private val node = MstExtendedField { - x * 2.0 + number(2.0) / x - number(16.0) / sin(x) - } - - private val mst = node.toExpression(DoubleField) - - private val asmPrimitive = node.compileToExpression(DoubleField) - private val xIdx = asmPrimitive.indexer.indexOf(x) - - private val asmGeneric = node.compileToExpression(DoubleField as Algebra) - - private val raw = Expression { args -> - val x = args[x]!! - x * 2.0 + 2.0 / x - 16.0 / sin(x) - } - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt deleted file mode 100644 index 6cc649fe9..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State -import org.openjdk.jmh.infra.Blackhole -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.algebra -import space.kscience.kmath.integration.gaussIntegrator -import space.kscience.kmath.integration.integrate -import space.kscience.kmath.integration.value -import space.kscience.kmath.operations.algebra - - -@State(Scope.Benchmark) -internal class IntegrationBenchmark { - - @Benchmark - fun doubleIntegration(blackhole: Blackhole) { - val res = Double.algebra.gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double -> - //sin(1 / x) - 1/x - }.value - blackhole.consume(res) - } - - @Benchmark - fun complexIntegration(blackhole: Blackhole) = with(Complex.algebra) { - val res = gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double -> -// sin(1 / x) + i * cos(1 / x) - 1/x - i/x - }.value - blackhole.consume(res) - } -} \ No newline at end of file diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt deleted file mode 100644 index 041f7e92a..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Blackhole -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State -import space.kscience.kmath.jafama.JafamaDoubleField -import space.kscience.kmath.jafama.StrictJafamaDoubleField -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.random.Random - -@State(Scope.Benchmark) -internal class JafamaBenchmark { - @Benchmark - fun jafama(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> - JafamaDoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } - } - - @Benchmark - fun core(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> - DoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } - } - - @Benchmark - fun strictJafama(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> - StrictJafamaDoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } - } -} - -private inline fun invokeBenchmarks(blackhole: Blackhole, expr: (Double) -> Double) { - contract { callsInPlace(expr, InvocationKind.AT_LEAST_ONCE) } - val rng = Random(0) - repeat(1000000) { blackhole.consume(expr(rng.nextDouble())) } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt deleted file mode 100644 index f7aac8199..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.commons.linear.CMLinearSpace -import space.kscience.kmath.commons.linear.lupSolver -import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM -import space.kscience.kmath.linear.invoke -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.linear.lupSolver -import space.kscience.kmath.operations.algebra -import kotlin.random.Random - -@State(Scope.Benchmark) -internal class MatrixInverseBenchmark { - private companion object { - private val random = Random(1224) - private const val dim = 100 - - private val space = Double.algebra.linearSpace - - //creating invertible matrix - private val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - private val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 } - private val matrix = space { l dot u } - } - - @Benchmark - fun kmathLupInversion(blackhole: Blackhole) { - blackhole.consume(Double.algebra.linearSpace.lupSolver().inverse(matrix)) - } - - @Benchmark - fun cmLUPInversion(blackhole: Blackhole) { - CMLinearSpace { - blackhole.consume(lupSolver().inverse(matrix)) - } - } - - @Benchmark - fun ejmlInverse(blackhole: Blackhole) { - EjmlLinearSpaceDDRM { - blackhole.consume(matrix.toEjml().inverse()) - } - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt deleted file mode 100644 index fb8d845e8..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.ones -import org.jetbrains.kotlinx.multik.ndarray.data.DN -import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.UnsafeKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.nd4j.nd4j -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.one -import space.kscience.kmath.tensors.core.tensorAlgebra -import space.kscience.kmath.viktor.viktorAlgebra - -@State(Scope.Benchmark) -internal class NDFieldBenchmark { - - @Benchmark - fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - - @Benchmark - fun boxingFieldAdd(blackhole: Blackhole) = with(genericField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - - @Benchmark - fun multikAdd(blackhole: Blackhole) = with(multikAlgebra) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - - @Benchmark - fun viktorAdd(blackhole: Blackhole) = with(viktorField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - - @Benchmark - fun tensorAdd(blackhole: Blackhole) = with(Double.tensorAlgebra) { - var res: DoubleTensor = one(shape) - repeat(n) { res = res + 1.0 } - blackhole.consume(res) - } - - @Benchmark - fun tensorInPlaceAdd(blackhole: Blackhole) = with(Double.tensorAlgebra) { - val res: DoubleTensor = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - - @OptIn(UnsafeKMathAPI::class) - @Benchmark - fun multikInPlaceAdd(blackhole: Blackhole) = with(multikAlgebra) { - val res = Multik.ones(shape.asArray(), DataType.DoubleDataType).wrap() - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - -// @Benchmark -// fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) { -// var res: StructureND = one(dim, dim) -// repeat(n) { res += 1.0 } -// blackhole.consume(res) -// } - - private companion object { - private const val dim = 1000 - private const val n = 100 - private val shape = ShapeND(dim, dim) - private val specializedField = DoubleField.ndAlgebra - private val genericField = BufferedFieldOpsND(DoubleField) - private val nd4jField = DoubleField.nd4j - private val viktorField = DoubleField.viktorAlgebra - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt deleted file mode 100644 index c4382374a..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.linear.matrix -import space.kscience.kmath.linear.symmetric -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.tensors.core.symEigJacobi -import space.kscience.kmath.tensors.core.symEigSvd -import space.kscience.kmath.tensors.core.tensorAlgebra -import kotlin.random.Random - -@State(Scope.Benchmark) -internal class TensorAlgebraBenchmark { - companion object { - private val random = Random(12224) - private const val dim = 30 - - private val matrix = DoubleField.linearSpace.matrix(dim, dim).symmetric { _, _ -> random.nextDouble() } - } - - @Benchmark - fun tensorSymEigSvd(blackhole: Blackhole) = with(Double.tensorAlgebra) { - blackhole.consume(symEigSvd(matrix, 1e-10)) - } - - @Benchmark - fun tensorSymEigJacobi(blackhole: Blackhole) = with(Double.tensorAlgebra) { - blackhole.consume(symEigJacobi(matrix, 50, 1e-10)) - } -} \ No newline at end of file diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt deleted file mode 100644 index f6d278d83..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import org.jetbrains.kotlinx.multik.default.DefaultEngine -import space.kscience.kmath.multik.MultikDoubleAlgebra - -val multikAlgebra = MultikDoubleAlgebra(DefaultEngine()) \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index fb2f7d8c7..9b2200cb4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,80 +1,68 @@ -import space.kscience.gradle.isInDevelopment -import space.kscience.gradle.useApache2Licence -import space.kscience.gradle.useSPCTeam +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import org.jetbrains.dokka.gradle.DokkaTask +import java.net.URL plugins { - id("space.kscience.gradle.project") - id("org.jetbrains.kotlinx.kover") version "0.6.0" + id("ru.mipt.npm.gradle.project") } allprojects { repositories { - maven("https://repo.kotlin.link") - maven("https://oss.sonatype.org/content/repositories/snapshots") + jcenter() + maven("https://clojars.org/repo") + maven("https://dl.bintray.com/egor-bogomolov/astminer/") + maven("https://dl.bintray.com/hotkeytlt/maven") + maven("https://jitpack.io") + maven{ + setUrl("http://logicrunch.research.it.uu.se/maven/") + isAllowInsecureProtocol = true + } mavenCentral() } group = "space.kscience" - version = "0.3.1" + version = "0.3.0-dev-6" } subprojects { if (name.startsWith("kmath")) apply() - plugins.withId("org.jetbrains.dokka") { - tasks.withType { - dependsOn(tasks["assemble"]) - + afterEvaluate { + tasks.withType { dokkaSourceSets.all { - val readmeFile = this@subprojects.projectDir.resolve("README.md") - if (readmeFile.exists()) includes.from(readmeFile) - val kotlinDirPath = "src/$name/kotlin" - val kotlinDir = file(kotlinDirPath) + val readmeFile = File(this@subprojects.projectDir, "./README.md") + if (readmeFile.exists()) + includes.setFrom(includes + readmeFile.absolutePath) - if (kotlinDir.exists()) sourceLink { - localDirectory.set(kotlinDir) - - remoteUrl.set( - java.net.URL("https://github.com/SciProgCentre/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath") - ) + arrayOf( + "http://ejml.org/javadoc/", + "https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/", + "https://deeplearning4j.org/api/latest/" + ).map { URL("${it}package-list") to URL(it) }.forEach { (a, b) -> + externalDocumentationLink { + packageListUrl.set(a) + url.set(b) + } } - - externalDocumentationLink("https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/") - externalDocumentationLink("https://deeplearning4j.org/api/latest/") - externalDocumentationLink("https://axelclk.bitbucket.io/symja/javadoc/") - - externalDocumentationLink( - "https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/", - "https://kotlin.github.io/kotlinx.coroutines/package-list", - ) - - externalDocumentationLink( - "https://breandan.net/kotlingrad/kotlingrad/", - "https://breandan.net/kotlingrad/kotlingrad/kotlingrad/package-list", - ) } } } } -readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") +readme { + readmeTemplate = file("docs/templates/README-TEMPLATE.md") +} ksciencePublish { - pom("https://github.com/SciProgCentre/kmath") { - useApache2Licence() - useSPCTeam() - } - github("kmath", "SciProgCentre") - space( - if (isInDevelopment) { - "https://maven.pkg.jetbrains.space/spc/p/sci/dev" - } else { - "https://maven.pkg.jetbrains.space/spc/p/sci/maven" - } - ) + github("kmath") + space() sonatype() } -apiValidation.nonPublicMarkers.add("space.kscience.kmath.UnstableKMathAPI") - -val multikVersion by extra("0.2.0") +apiValidation { + nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts deleted file mode 100644 index 734f60091..000000000 --- a/buildSrc/build.gradle.kts +++ /dev/null @@ -1,34 +0,0 @@ -plugins { - `kotlin-dsl` - `version-catalog` -} - -repositories { - mavenLocal() - maven("https://repo.kotlin.link") - mavenCentral() - gradlePluginPortal() -} - -val toolsVersion = spclibs.versions.tools.get() -val kotlinVersion = spclibs.versions.kotlin.asProvider().get() -val benchmarksVersion = spclibs.versions.kotlinx.benchmark.get() - -dependencies { - api("space.kscience:gradle-tools:$toolsVersion") - //plugins form benchmarks - api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.4.7") - //api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") - //to be used inside build-script only - //implementation(spclibs.kotlinx.serialization.json) - implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.+") -} - -kotlin{ - jvmToolchain{ - languageVersion.set(JavaLanguageVersion.of(11)) - } - sourceSets.all { - languageSettings.optIn("kotlin.OptIn") - } -} diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts deleted file mode 100644 index e6b69b0b3..000000000 --- a/buildSrc/settings.gradle.kts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -rootProject.name = "kmath" - -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") - -dependencyResolutionManagement { - val projectProperties = java.util.Properties() - file("../gradle.properties").inputStream().use { - projectProperties.load(it) - } - - projectProperties.forEach { key, value -> - extra.set(key.toString(), value) - } - - - val toolsVersion: String = projectProperties["toolsVersion"].toString() - - repositories { - mavenLocal() - maven("https://repo.kotlin.link") - mavenCentral() - gradlePluginPortal() - } - - versionCatalogs { - create("spclibs") { - from("space.kscience:version-catalog:$toolsVersion") - } - } -} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt deleted file mode 100644 index 3a4fcdc79..000000000 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -data class JmhReport( - val jmhVersion: String, - val benchmark: String, - val mode: String, - val threads: Int, - val forks: Int, - val jvm: String, - val jvmArgs: List, - val jdkVersion: String, - val vmName: String, - val vmVersion: String, - val warmupIterations: Int, - val warmupTime: String, - val warmupBatchSize: Int, - val measurementIterations: Int, - val measurementTime: String, - val measurementBatchSize: Int, - val params: Map = emptyMap(), - val primaryMetric: PrimaryMetric, - val secondaryMetrics: Map, -) { - interface Metric { - val score: Double - val scoreError: Double - val scoreConfidence: List - val scorePercentiles: Map - val scoreUnit: String - } - - data class PrimaryMetric( - override val score: Double, - override val scoreError: Double, - override val scoreConfidence: List, - override val scorePercentiles: Map, - override val scoreUnit: String, - val rawDataHistogram: List>>>? = null, - val rawData: List>? = null, - ) : Metric - - data class SecondaryMetric( - override val score: Double, - override val scoreError: Double, - override val scoreConfidence: List, - override val scorePercentiles: Map, - override val scoreUnit: String, - val rawData: List>, - ) : Metric -} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt deleted file mode 100644 index a3a475885..000000000 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import kotlinx.benchmark.gradle.BenchmarksExtension -import org.gradle.api.Project -import space.kscience.gradle.KScienceReadmeExtension -import java.time.LocalDateTime -import java.time.ZoneId -import java.time.format.DateTimeFormatter -import java.time.format.DateTimeFormatterBuilder -import java.time.format.SignStyle -import java.time.temporal.ChronoField.* -import java.util.* - -private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run { - parseCaseInsensitive() - appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) - appendLiteral('-') - appendValue(MONTH_OF_YEAR, 2) - appendLiteral('-') - appendValue(DAY_OF_MONTH, 2) - appendLiteral('T') - appendValue(HOUR_OF_DAY, 2) - appendLiteral('.') - appendValue(MINUTE_OF_HOUR, 2) - optionalStart() - appendLiteral('.') - appendValue(SECOND_OF_MINUTE, 2) - optionalStart() - appendFraction(NANO_OF_SECOND, 0, 9, true) - optionalStart() - appendOffsetId() - optionalStart() - appendLiteral('[') - parseCaseSensitive() - appendZoneRegionId() - appendLiteral(']') - toFormatter() -} - -private fun noun(number: Number, singular: String, plural: String) = if (number.toLong() == 1L) singular else plural - -private val jsonMapper = jacksonObjectMapper() - -fun Project.addBenchmarkProperties() { - val benchmarksProject = this - rootProject.subprojects.forEach { p -> - p.extensions.findByType(KScienceReadmeExtension::class.java)?.run { - benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> - property("benchmark${cfg.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }}") { - val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}") - - val resDirectory = launches.listFiles()?.maxByOrNull { - LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant() - } - - if (resDirectory == null || !(resDirectory.resolve("jvm.json")).exists()) { - "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." - } else { - val reports: List = jsonMapper.readValue>(resDirectory.resolve("jvm.json")) - - buildString { - appendLine("
") - appendLine("") - appendLine("Report for benchmark configuration ${cfg.name}") - appendLine("") - appendLine() - val first = reports.first() - - appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:") - appendLine() - appendLine("```") - appendLine("${first.jvm} ${ - first.jvmArgs.joinToString(" ") - }") - appendLine("```") - - appendLine("* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${ - noun(first.warmupIterations, "iteration", "iterations") - } by ${first.warmupTime} and ${first.measurementIterations} measurement ${ - noun(first.measurementIterations, "iteration", "iterations") - } by ${first.measurementTime}.") - - appendLine() - appendLine("| Benchmark | Score |") - appendLine("|:---------:|:-----:|") - - reports.forEach { report -> - appendLine("|`${report.benchmark}`|${report.primaryMetric.score} ± ${report.primaryMetric.scoreError} ${report.primaryMetric.scoreUnit}|") - } - - appendLine("
") - } - } - } - } - } - } -} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt deleted file mode 100644 index d973ebae4..000000000 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("KDocUnresolvedReference") - -package space.kscience.kmath.ejml.codegen - -import org.intellij.lang.annotations.Language -import java.io.File - -private fun Appendable.appendEjmlVector(type: String, ejmlMatrixType: String) { - @Language("kotlin") val text = """/** - * [EjmlVector] specialization for [$type]. - */ -public class Ejml${type}Vector(override val origin: M) : EjmlVector<$type, M>(origin) { - init { - require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } - } - - override operator fun get(index: Int): $type = origin[0, index] -}""" - appendLine(text) - appendLine() -} - -private fun Appendable.appendEjmlMatrix(type: String, ejmlMatrixType: String) { - val text = """/** - * [EjmlMatrix] specialization for [$type]. - */ -public class Ejml${type}Matrix(override val origin: M) : EjmlMatrix<$type, M>(origin) { - override operator fun get(i: Int, j: Int): $type = origin[i, j] -}""" - appendLine(text) - appendLine() -} - -private fun Appendable.appendEjmlLinearSpace( - type: String, - kmathAlgebra: String, - ejmlMatrixParentTypeMatrix: String, - ejmlMatrixType: String, - ejmlMatrixDenseType: String, - ops: String, - denseOps: String, - isDense: Boolean, -) { - @Language("kotlin") val text = """/** - * [EjmlLinearSpace] implementation based on [CommonOps_$ops], [DecompositionFactory_${ops}] operations and - * [${ejmlMatrixType}] matrices. - */ -public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, $ejmlMatrixType>() { - /** - * The [${kmathAlgebra}] reference. - */ - override val elementAlgebra: $kmathAlgebra get() = $kmathAlgebra - - @Suppress("UNCHECKED_CAST") - override fun Matrix<${type}>.toEjml(): Ejml${type}Matrix<${ejmlMatrixType}> = when { - this is Ejml${type}Matrix<*> && origin is $ejmlMatrixType -> this as Ejml${type}Matrix<${ejmlMatrixType}> - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point<${type}>.toEjml(): Ejml${type}Vector<${ejmlMatrixType}> = when { - this is Ejml${type}Vector<*> && origin is $ejmlMatrixType -> this as Ejml${type}Vector<${ejmlMatrixType}> - else -> Ejml${type}Vector(${ejmlMatrixType}(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: ${kmathAlgebra}.(i: Int, j: Int) -> ${type}, - ): Ejml${type}Matrix<${ejmlMatrixType}> = ${ejmlMatrixType}(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: ${kmathAlgebra}.(Int) -> ${type}, - ): Ejml${type}Vector<${ejmlMatrixType}> = Ejml${type}Vector(${ejmlMatrixType}(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = Ejml${type}Matrix(this) - private fun T.wrapVector() = Ejml${type}Vector(this) - - override fun Matrix<${type}>.unaryMinus(): Matrix<${type}> = this * elementAlgebra { -one } - - override fun Matrix<${type}>.dot(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix<${type}>.dot(vector: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix<${type}>.minus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - - CommonOps_${ops}.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out,${ - if (isDense) "" else - """ - null, - null,""" - } - ) - - return out.wrapMatrix() - } - - override operator fun Matrix<${type}>.times(value: ${type}): Ejml${type}Matrix<${ejmlMatrixType}> { - val res = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point<${type}>.unaryMinus(): Ejml${type}Vector<${ejmlMatrixType}> { - val res = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix<${type}>.plus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - - CommonOps_${ops}.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out,${ - if (isDense) "" else - """ - null, - null,""" - } - ) - - return out.wrapMatrix() - } - - override fun Point<${type}>.plus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - - CommonOps_${ops}.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out,${ - if (isDense) "" else - """ - null, - null,""" - } - ) - - return out.wrapVector() - } - - override fun Point<${type}>.minus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - - CommonOps_${ops}.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out,${ - if (isDense) "" else - """ - null, - null,""" - } - ) - - return out.wrapVector() - } - - override fun ${type}.times(m: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> = m * this - - override fun Point<${type}>.times(value: ${type}): Ejml${type}Vector<${ejmlMatrixType}> { - val res = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this - - @UnstableKMathAPI - override fun computeFeature(structure: Matrix<${type}>, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - ${ - if (isDense) - """ InverseMatrixFeature::class -> object : InverseMatrixFeature<${type}> { - override val inverse: Matrix<${type}> by lazy { - val res = origin.copy() - CommonOps_${ops}.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature<${type}> { - override val determinant: $type by lazy { CommonOps_${ops}.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<${type}> { - private val svd by lazy { - DecompositionFactory_${ops}.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix<${type}> by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix<${type}> by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix<${type}> by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point<${type}> by lazy { ${type}Buffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature<${type}> { - private val qr by lazy { - DecompositionFactory_${ops}.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix<${type}> by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> { - override val l: Matrix<${type}> by lazy { - val cholesky = - DecompositionFactory_${ops}.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix().withFeature(LFeature) - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature<${type}> { - private val lup by lazy { - DecompositionFactory_${ops}.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix<${type}> by lazy { - lup.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix<${type}> by lazy { - lup.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val p: Matrix<${type}> by lazy { lup.getRowPivot(null).wrapMatrix() } - }""" else """ QRDecompositionFeature::class -> object : QRDecompositionFeature<$type> { - private val qr by lazy { - DecompositionFactory_${ops}.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix<${type}> by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> { - override val l: Matrix<${type}> by lazy { - val cholesky = - DecompositionFactory_${ops}.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as ${ejmlMatrixParentTypeMatrix}).wrapMatrix().withFeature(LFeature) - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature<${type}>, DeterminantFeature<${type}>, InverseMatrixFeature<${type}> { - private val lu by lazy { - DecompositionFactory_${ops}.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix<${type}> by lazy { - lu.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix<${type}> by lazy { - lu.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val inverse: Matrix<${type}> by lazy { - var a = origin - val inverse = ${ejmlMatrixDenseType}(1, 1) - val solver = LinearSolverFactory_${ops}.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_${denseOps}.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: $type by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - }""" - } - - else -> null - }?.let{ - type.cast(it) - } - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix<${type}>, b: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { - val res = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.solve(${ejmlMatrixType}(a.toEjml().origin), ${ejmlMatrixType}(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix<${type}>, b: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { - val res = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.solve(${ejmlMatrixType}(a.toEjml().origin), ${ejmlMatrixType}(b.toEjml().origin), res) - return Ejml${type}Vector(res) - } -}""" - appendLine(text) - appendLine() -} - - -/** - * Generates routine EJML classes. - */ -fun ejmlCodegen(outputFile: String): Unit = File(outputFile).run { - parentFile.mkdirs() - - writer().use { - it.appendLine("/*") - it.appendLine(" * Copyright 2018-2021 KMath contributors.") - it.appendLine(" * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.") - it.appendLine(" */") - it.appendLine() - it.appendLine("/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */") - it.appendLine() - it.appendLine("package space.kscience.kmath.ejml") - it.appendLine() - it.appendLine("""import org.ejml.data.* -import org.ejml.dense.row.CommonOps_DDRM -import org.ejml.dense.row.CommonOps_FDRM -import org.ejml.dense.row.factory.DecompositionFactory_DDRM -import org.ejml.dense.row.factory.DecompositionFactory_FDRM -import org.ejml.sparse.FillReducing -import org.ejml.sparse.csc.CommonOps_DSCC -import org.ejml.sparse.csc.CommonOps_FSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC -import space.kscience.kmath.linear.* -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.FloatField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.FloatBuffer -import kotlin.reflect.KClass -import kotlin.reflect.cast""") - it.appendLine() - it.appendEjmlVector("Double", "DMatrix") - it.appendEjmlVector("Float", "FMatrix") - it.appendEjmlMatrix("Double", "DMatrix") - it.appendEjmlMatrix("Float", "FMatrix") - it.appendEjmlLinearSpace("Double", "DoubleField", "DMatrix", "DMatrixRMaj", "DMatrixRMaj", "DDRM", "DDRM", true) - it.appendEjmlLinearSpace("Float", "FloatField", "FMatrix", "FMatrixRMaj", "FMatrixRMaj", "FDRM", "FDRM", true) - - it.appendEjmlLinearSpace( - type = "Double", - kmathAlgebra = "DoubleField", - ejmlMatrixParentTypeMatrix = "DMatrix", - ejmlMatrixType = "DMatrixSparseCSC", - ejmlMatrixDenseType = "DMatrixRMaj", - ops = "DSCC", - denseOps = "DDRM", - isDense = false, - ) - - it.appendEjmlLinearSpace( - type = "Float", - kmathAlgebra = "FloatField", - ejmlMatrixParentTypeMatrix = "FMatrix", - ejmlMatrixType = "FMatrixSparseCSC", - ejmlMatrixDenseType = "FMatrixRMaj", - ops = "FSCC", - denseOps = "FDRM", - isDense = false, - ) - } -} diff --git a/docs/algebra.md b/docs/algebra.md index 20158a125..84693bb81 100644 --- a/docs/algebra.md +++ b/docs/algebra.md @@ -1,45 +1,85 @@ # Algebraic Structures and Algebraic Elements -The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an -operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up, -say `Group`. Next one needs to run the actual operation in the context: +The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an +operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up, +say `Space`. Next one needs to run the actual operation in the context: ```kotlin import space.kscience.kmath.operations.* val a: T = ... val b: T = ... -val group: Group = ... +val space: Space = ... -val c = group { a + b } +val c = space { a + b } ``` -At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in -mathematics, one could draw up different operations on same objects. For example, one could use different types of +At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in +mathematics, one could draw up different operations on same objects. For example, one could use different types of geometry for vectors. ## Algebraic Structures -Primary mathematical contexts have the following hierarchy: +Mathematical contexts have the following hierarchy: -`Field <: Ring <: Group <: Algebra` +**Algebra** ← **Space** ← **Ring** ← **Field** These interfaces follow real algebraic structures: -- [Group](https://mathworld.wolfram.com/Group.html) defines addition, its identity element (i.e., 0) and additive - inverse (-x); -- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its identity element (i.e., 1); +- [Space](https://mathworld.wolfram.com/VectorSpace.html) defines addition, its neutral element (i.e. 0) and scalar +multiplication; +- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1); - [Field](http://mathworld.wolfram.com/Field.html) adds division operation. A typical implementation of `Field` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space`. In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate -interface. Also, contexts may have operations, which produce elements outside the context. For example, `Matrix.dot` -operation produces a matrix with new dimensions, which can be incompatible with initial matrix in linear operations. +interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot` +operation produces a matrix with new dimensions, which can be incompatible with initial matrix in terms of linear +operations. + +## Algebraic Element + +To achieve more familiar behavior (where you apply operations directly to mathematical objects), without involving +contexts KMath submits special type objects called `MathElement`. A `MathElement` is basically some object coupled to +a mathematical context. For example `Complex` is the pair of real numbers representing real and imaginary parts, +but it also holds reference to the `ComplexField` singleton, which allows performing direct operations on `Complex` +numbers without explicit involving the context like: + +```kotlin +import space.kscience.kmath.operations.* + +// Using elements +val c1 = Complex(1.0, 1.0) +val c2 = Complex(1.0, -1.0) +val c3 = c1 + c2 + 3.0.toComplex() + +// Using context +val c4 = ComplexField { c1 + i - 2.0 } +``` + +Both notations have their pros and cons. + +The hierarchy for algebraic elements follows the hierarchy for the corresponding algebraic structures. + +**MathElement** ← **SpaceElement** ← **RingElement** ← **FieldElement** + +`MathElement` is the generic common ancestor of the class with context. + +One major distinction between algebraic elements and algebraic contexts is that elements have three type +parameters: + +1. The type of elements, the field operates on. +2. The self-type of the element returned from operation (which has to be an algebraic element). +3. The type of the algebra over first type-parameter. + +The middle type is needed for of algebra members do not store context. For example, it is impossible to add a context +to regular `Double`. The element performs automatic conversions from context types and back. One should use context +operations in all performance-critical places. The performance of element operations is not guaranteed. ## Spaces and Fields -KMath introduces contexts for builtin algebraic structures: +KMath submits both contexts and elements for builtin algebraic structures: ```kotlin import space.kscience.kmath.operations.* @@ -62,13 +102,13 @@ val c2 = ComplexField { c1 - 1.0 } // Returns: Complex(re=0.0, im=2.0) val c3 = ComplexField { c1 - i * 2.0 } ``` -**Note**: In theory it is possible to add behaviors directly to the context, but as for now Kotlin does not support -that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and +**Note**: In theory it is possible to add behaviors directly to the context, but as for now Kotlin does not support +that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and [KEEP-176](https://github.com/Kotlin/KEEP/pull/176) for updates. ## Nested fields -Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex +Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex elements like so: ```kotlin @@ -78,9 +118,8 @@ val element = NDElement.complex(shape = intArrayOf(2, 2)) { index: IntArray -> ``` The `element` in this example is a member of the `Field` of 2D structures, each element of which is a member of its own -`ComplexField`. It is important one does not need to create a special n-d class to hold complex numbers and implement -operations on it, one just needs to provide a field for its elements. +`ComplexField`. It is important one does not need to create a special n-d class to hold complex +numbers and implement operations on it, one just needs to provide a field for its elements. -**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts -like +**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts like `MemorySpec`. diff --git a/docs/buffers.md b/docs/buffers.md index e7573497e..679bd4e78 100644 --- a/docs/buffers.md +++ b/docs/buffers.md @@ -1,20 +1,17 @@ # Buffers -Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write ( -with `MutableBuffer`). There are different types of buffers: +Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write (with `MutableBuffer`). +There are different types of buffers: -* Primitive buffers wrapping like `DoubleBuffer` which are wrapping primitive arrays. +* Primitive buffers wrapping like `RealBuffer` which are wrapping primitive arrays. * Boxing `ListBuffer` wrapping a list * Functionally defined `VirtualBuffer` which does not hold a state itself, but provides a function to calculate value * `MemoryBuffer` allows direct allocation of objects in continuous memory block. -Some kmath features require a `BufferFactory` class to operate properly. A general convention is to use functions -defined in -`Buffer` and `MutableBuffer` companion classes. For example factory `Buffer.Companion::auto` in most cases creates the -most suitable buffer for given reified type (for types with custom memory buffer it still better to use their -own `MemoryBuffer.create()` factory). +Some kmath features require a `BufferFactory` class to operate properly. A general convention is to use functions defined in +`Buffer` and `MutableBuffer` companion classes. For example factory `Buffer.Companion::auto` in most cases creates the most suitable +buffer for given reified type (for types with custom memory buffer it still better to use their own `MemoryBuffer.create()` factory). ## Buffer performance -One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers -instead . +One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers instead diff --git a/docs/codestyle.md b/docs/codestyle.md index 73ba5f754..541dc4973 100644 --- a/docs/codestyle.md +++ b/docs/codestyle.md @@ -1,20 +1,26 @@ # Coding Conventions -Generally, KMath code follows general [Kotlin coding conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but with a number of small changes and clarifications. +KMath code follows general [Kotlin conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but +with a number of small changes and clarifications. ## Utility Class Naming -Filename should coincide with a name of one of the classes contained in the file or start with small letter and describe its contents. +Filename should coincide with a name of one of the classes contained in the file or start with small letter and +describe its contents. -The code convention [here](https://kotlinlang.org/docs/reference/coding-conventions.html#source-file-names) says that file names should start with a capital letter even if file does not contain classes. Yet starting utility classes and aggregators with a small letter seems to be a good way to visually separate those files. +The code convention [here](https://kotlinlang.org/docs/reference/coding-conventions.html#source-file-names) says that +file names should start with a capital letter even if file does not contain classes. Yet starting utility classes and +aggregators with a small letter seems to be a good way to visually separate those files. This convention could be changed in future in a non-breaking way. ## Private Variable Naming -Private variables' names may start with underscore `_` for of the private mutable variable is shadowed by the public read-only value with the same meaning. +Private variables' names may start with underscore `_` for of the private mutable variable is shadowed by the public +read-only value with the same meaning. -This rule does not permit underscores in names, but it is sometimes useful to "underscore" the fact that public and private versions draw up the same entity. It is allowed only for private variables. +This rule does not permit underscores in names, but it is sometimes useful to "underscore" the fact that public and +private versions draw up the same entity. It is allowed only for private variables. This convention could be changed in future in a non-breaking way. @@ -24,4 +30,5 @@ Use one-liners when they occupy single code window line both for functions and p `val b: String get() = "fff"`. The same should be performed with multiline expressions when they could be cleanly separated. -There is no universal consensus whenever use `fun a() = ...` or `fun a() { return ... }`. Yet from reader outlook one-lines seem to better show that the property or function is easily calculated. +There is no universal consensus whenever use `fun a() = ...` or `fun a() { return ... }`. Yet from reader outlook +one-lines seem to better show that the property or function is easily calculated. diff --git a/docs/contexts.md b/docs/contexts.md index c26333860..58b198046 100644 --- a/docs/contexts.md +++ b/docs/contexts.md @@ -2,17 +2,18 @@ ## The problem -A known problem for implementing mathematics in statically-typed languages (but not only in them) is that different sets -of mathematical operators can be defined on the same mathematical objects. Sometimes there is no single way to treat -some operations, including basic arithmetic operations, on a Java/Kotlin `Number`. Sometimes there are different ways to -define the same structure, such as Euclidean and elliptic geometry vector spaces over real vectors. Another problem -arises when one wants to add some kind of behavior to an existing entity. In dynamic languages those problems are -usually solved by adding dynamic context-specific behaviors at runtime, but this solution has a lot of drawbacks. +A known problem for implementing mathematics in statically-typed languages (but not only in them) is that different +sets of mathematical operators can be defined on the same mathematical objects. Sometimes there is no single way to +treat some operations, including basic arithmetic operations, on a Java/Kotlin `Number`. Sometimes there are different ways to +define the same structure, such as Euclidean and elliptic geometry vector spaces over real vectors. Another problem arises when +one wants to add some kind of behavior to an existing entity. In dynamic languages those problems are usually solved +by adding dynamic context-specific behaviors at runtime, but this solution has a lot of drawbacks. ## Context-oriented approach -One possible solution to these problems is to divorce numerical representations from behaviors. For example in Kotlin -one can define a separate class representing some entity without any operations, ex. a complex number: +One possible solution to these problems is to divorce numerical representations from behaviors. +For example in Kotlin one can define a separate class which represents some entity without any operations, +ex. a complex number: ```kotlin data class Complex(val re: Double, val im: Double) @@ -27,10 +28,9 @@ object ComplexOperations { } ``` -In Java, applying such external operations could be cumbersome, but Kotlin has a unique feature that allows us -implement this -naturally: [extensions with receivers](https://kotlinlang.org/docs/reference/extensions.html#extension-functions). In -Kotlin, an operation on complex number could be implemented as: +In Java, applying such external operations could be very cumbersome, but Kotlin has a unique feature which allows us +implement this naturally: [extensions with receivers](https://kotlinlang.org/docs/reference/extensions.html#extension-functions). +In Kotlin, an operation on complex number could be implemented as: ```kotlin with(ComplexOperations) { c1 + c2 - c3 } @@ -52,20 +52,20 @@ In KMath, contexts are not only responsible for operations, but also for raw obj ### Type classes -An obvious candidate to get more or less the same functionality is the type class, which allows one to bind a behavior -to a specific type without modifying the type itself. On the plus side, type classes do not require explicit context +An obvious candidate to get more or less the same functionality is the type class, which allows one to bind a behavior to +a specific type without modifying the type itself. On the plus side, type classes do not require explicit context declaration, so the code looks cleaner. On the minus side, if there are different sets of behaviors for the same types, -it is impossible to combine them into one module. Also, unlike type classes, context can have parameters or even state. -For example in KMath, sizes and strides for `NDElement` or `Matrix` could be moved to context to optimize performance in -case of a large amount of structures. +it is impossible to combine them into one module. Also, unlike type classes, context can have parameters or even +state. For example in KMath, sizes and strides for `NDElement` or `Matrix` could be moved to context to optimize +performance in case of a large amount of structures. ### Wildcard imports and importing-on-demand -Sometimes, one may wish to use a single context throughout a file. In this case, is possible to import all members from -a package or file, via `import context.complex.*`. Effectively, this is the same as enclosing an entire file with a -single context. However, when using multiple contexts, this technique can introduce operator ambiguity, due to namespace -pollution. If there are multiple scoped contexts that define the same operation, it is still possible to import -specific operations as needed, without using an explicit context with extension functions, for example: +Sometimes, one may wish to use a single context throughout a file. In this case, is possible to import all members +from a package or file, via `import context.complex.*`. Effectively, this is the same as enclosing an entire file +with a single context. However when using multiple contexts, this technique can introduce operator ambiguity, due to +namespace pollution. If there are multiple scoped contexts which define the same operation, it is still possible to +to import specific operations as needed, without using an explicit context with extension functions, for example: ``` import context.complex.op1 diff --git a/docs/diagrams/core.puml b/docs/diagrams/core.puml deleted file mode 100644 index 87f8f2e2d..000000000 --- a/docs/diagrams/core.puml +++ /dev/null @@ -1,1020 +0,0 @@ -@startuml -interface "ColumnarData" { - size: Int -} -interface "XYColumnarData" { - x: Buffer - y: Buffer -} -interface "XYErrorColumnarData" { - yErr: Buffer -} -interface "XYZColumnarData" { - z: Buffer -} -interface "Domain" { - dimension: Int -} -interface "DoubleDomain" { - -} -class "HyperSquareDomain" { - lower: Buffer - upper: Buffer -} -class "UnconstrainedDomain" { - dimension: Int -} -class "UnivariateDomain" { - range: ClosedFloatingPointRange -} -interface "DifferentiableExpression" { - -} -interface "SpecialDifferentiableExpression" { - -} -abstract "FirstDerivativeExpression" { - -} -interface "AutoDiffProcessor" { - -} -interface "Expression" { - -} -interface "ExpressionAlgebra" { - -} -abstract "FunctionalExpressionAlgebra" { - algebra: A -} -class "FunctionalExpressionGroup" { - algebra: A -} -class "FunctionalExpressionRing" { - algebra: A -} -class "FunctionalExpressionField" { - algebra: A -} -class "FunctionalExpressionExtendedField" { - algebra: A -} -interface "MST" { - -} -class "Numeric" { - value: Number -} -class "Unary" { - operation: String - value: MST -} -class "Binary" { - operation: String - left: MST - right: MST -} -class "InnerAlgebra" { - algebra: Algebra - arguments: Map -} -class "MstNumericAlgebra" { - number() - bindSymbolOrNull() - bindSymbol() - unaryOperationFunction() - binaryOperationFunction() -} -class "MstGroup" { - zero: MST.Numericnumber() - bindSymbolOrNull() - add() - unaryPlus() - unaryMinus() - minus() - scale() - binaryOperationFunction() - unaryOperationFunction() -} -class "MstRing" { - zero: MST.Numeric - one: MST.Numericnumber() - bindSymbolOrNull() - add() - scale() - multiply() - unaryPlus() - unaryMinus() - minus() - binaryOperationFunction() - unaryOperationFunction() -} -class "MstField" { - zero: MST.Numeric - one: MST.NumericbindSymbolOrNull() - number() - add() - scale() - multiply() - divide() - unaryPlus() - unaryMinus() - minus() - binaryOperationFunction() - unaryOperationFunction() -} -class "MstExtendedField" { - zero: MST.Numeric - one: MST.NumericbindSymbolOrNull() - number() - sin() - cos() - tan() - asin() - acos() - atan() - sinh() - cosh() - tanh() - asinh() - acosh() - atanh() - add() - sqrt() - scale() - multiply() - divide() - unaryPlus() - unaryMinus() - minus() - power() - exp() - ln() - binaryOperationFunction() - unaryOperationFunction() -} -class "MstLogicAlgebra" { - bindSymbolOrNull() - const() - not() - and() - or() - xor() -} -class "AutoDiffValue" { - value: T -} -class "DerivationResult" { - value: T - derivativeValues: Map - context: Field -} -class "SimpleAutoDiffField" { - context: F - bindings: Map -} -class "AutoDiffVariableWithDerivative" { - identity: String - value: T - d: T -} -class "SimpleAutoDiffExpression" { - field: F - function: SimpleAutoDiffField -} -class "SimpleAutoDiffExtendedField" { - context: F - bindings: Map -} -interface "Symbol" { - identity: String -} -class "StringSymbol" { - identity: String -} -interface "SymbolIndexer" { - symbols: List -} -class "SimpleSymbolIndexer" { - symbols: List -} -class "BufferedLinearSpace" { - elementAlgebra: A - bufferFactory: BufferFactory -} -interface "LinearSolver" { - -} -interface "LinearSpace" { - elementAlgebra: A -} -class "LupDecomposition" { - context: LinearSpace - elementContext: Field - lu: Matrix - pivot: IntArray - even: Boolean -} -class "MatrixBuilder" { - linearSpace: LinearSpace - rows: Int - columns: Int -} -class "SymmetricMatrixFeature" { - -} -interface "MatrixFeature" { - -} -interface "DiagonalFeature" { - -} -class "ZeroFeature" { - -} -class "UnitFeature" { - -} -interface "InverseMatrixFeature" { - inverse: Matrix -} -interface "DeterminantFeature" { - determinant: T -} -class "LFeature" { - -} -class "UFeature" { - -} -interface "LUDecompositionFeature" { - l: Matrix - u: Matrix -} -interface "LupDecompositionFeature" { - l: Matrix - u: Matrix - p: Matrix -} -class "OrthogonalFeature" { - -} -interface "QRDecompositionFeature" { - q: Matrix - r: Matrix -} -interface "CholeskyDecompositionFeature" { - l: Matrix -} -interface "SingularValueDecompositionFeature" { - u: Matrix - s: Matrix - v: Matrix - singularValues: Point -} -class "MatrixWrapper" { - origin: Matrix - features: FeatureSet -} -class "TransposedFeature" { - original: Matrix -} -class "VirtualMatrix" { - rowNum: Int - colNum: Int - generator: (i:Int,j:Int)->T -} -class "UnstableKMathAPI" { - -} -class "PerformancePitfall" { - message: String -} -interface "Featured" { - -} -interface "Feature" { - key: FeatureKey -} -class "FeatureSet" { - features: Map -} -interface "Loggable" { - -} -class "ShapeMismatchException" { - expected: IntArray - actual: IntArray -} -interface "AlgebraND" { - shape: IntArray - elementContext: C -} -interface "GroupND" { - -} -interface "RingND" { - -} -interface "FieldND" { - -} -interface "BufferAlgebraND" { - strides: Strides - bufferFactory: BufferFactory - buffer: Buffer -} -class "BufferedGroupND" { - shape: IntArray - elementContext: A - bufferFactory: BufferFactory -} -class "BufferedRingND" { - shape: IntArray - elementContext: R - bufferFactory: BufferFactory -} -class "BufferedFieldND" { - shape: IntArray - elementContext: R - bufferFactory: BufferFactory -} -class "BufferND" { - strides: Strides - buffer: Buffer -} -class "MutableBufferND" { - strides: Strides - mutableBuffer: MutableBuffer -} -class "DoubleFieldND" { - shape: IntArray -} -class "ShortRingND" { - shape: IntArray -} -interface "Structure1D" { - dimension: Int -} -interface "MutableStructure1D" { - -} -class "Structure1DWrapper" { - structure: StructureND -} -class "MutableStructure1DWrapper" { - structure: MutableStructureND -} -class "Buffer1DWrapper" { - buffer: Buffer -} -class "MutableBuffer1DWrapper" { - buffer: MutableBuffer -} -interface "Structure2D" { - rowNum: Int - colNum: Int - shape: IntArray - rows: List - columns: List -} -interface "MutableStructure2D" { - rows: List - columns: List -} -class "Structure2DWrapper" { - structure: StructureND -} -class "MutableStructure2DWrapper" { - structure: MutableStructureND -} -interface "StructureFeature" { - -} -interface "StructureND" { - shape: IntArray - dimension: Int -} -interface "MutableStructureND" { - -} -interface "Strides" { - shape: IntArray - strides: IntArray - linearSize: Int -} -class "DefaultStrides" { - shape: IntArray -} -class "KMathContext" { - -} -interface "Algebra" { - -} -interface "GroupOperations" { - -} -interface "Group" { - zero: T -} -interface "RingOperations" { - -} -interface "Ring" { - one: T -} -interface "FieldOperations" { - -} -interface "Field" { - -} -interface "AlgebraElement" { - context: C -} -interface "GroupElement" { - -} -interface "RingElement" { - -} -interface "FieldElement" { - -} -class "BigIntField" { - zero: BigInt - one: BigIntnumber() - unaryMinus() - add() - scale() - multiply() - divide() - unaryPlus() - unaryMinus() -} -class "BigInt" { - sign: Byte - magnitude: Magnitude -} -interface "BufferAlgebra" { - bufferFactory: BufferFactory - elementAlgebra: A -} -class "BufferField" { - bufferFactory: BufferFactory - elementAlgebra: A - size: Int -} -interface "LogicAlgebra" { - -} -class "BooleanAlgebra" { - const() - not() - and() - or() - xor() -} -interface "ExtendedFieldOperations" { - -} -interface "ExtendedField" { - -} -class "DoubleField" { - zero: Double - one: Doublenumber() - binaryOperationFunction() - add() - multiply() - divide() - scale() - sin() - cos() - tan() - acos() - asin() - atan() - sinh() - cosh() - tanh() - asinh() - acosh() - atanh() - sqrt() - power() - exp() - ln() - norm() - unaryMinus() - plus() - minus() - times() - div() -} -class "FloatField" { - zero: Float - one: Floatnumber() - binaryOperationFunction() - add() - scale() - multiply() - divide() - sin() - cos() - tan() - acos() - asin() - atan() - sinh() - cosh() - tanh() - asinh() - acosh() - atanh() - sqrt() - power() - exp() - ln() - norm() - unaryMinus() - plus() - minus() - times() - div() -} -class "IntRing" { - zero: Int - one: Intnumber() - add() - multiply() - norm() - unaryMinus() - plus() - minus() - times() -} -class "ShortRing" { - zero: Short - one: Shortnumber() - add() - multiply() - norm() - unaryMinus() - plus() - minus() - times() -} -class "ByteRing" { - zero: Byte - one: Bytenumber() - add() - multiply() - norm() - unaryMinus() - plus() - minus() - times() -} -class "LongRing" { - zero: Long - one: Longnumber() - add() - multiply() - norm() - unaryMinus() - plus() - minus() - times() -} -interface "NumericAlgebra" { - -} -interface "ScaleOperations" { - -} -interface "NumbersAddOperations" { - -} -interface "TrigonometricOperations" { - -} -interface "PowerOperations" { - -} -interface "ExponentialOperations" { - -} -interface "Norm" { - -} -interface "Buffer" { - size: Int -} -interface "MutableBuffer" { - -} -class "ListBuffer" { - list: List -} -class "MutableListBuffer" { - list: MutableList -} -class "ArrayBuffer" { - array: Array -} -class "ReadOnlyBuffer" { - buffer: MutableBuffer -} -class "VirtualBuffer" { - size: Int - generator: (Int)->T -} -class "BufferAccessor2D" { - rowNum: Int - colNum: Int - factory: MutableBufferFactory -} -class "Row" { - buffer: MutableBuffer - rowIndex: Int -} -class "DoubleBuffer" { - array: DoubleArray -} -class "DoubleBufferFieldOperations" { - unaryMinus() - add() - multiply() - divide() - sin() - cos() - tan() - asin() - acos() - atan() - sinh() - cosh() - tanh() - asinh() - acosh() - atanh() - power() - exp() - ln() -} -class "DoubleL2Norm" { - norm() -} -class "DoubleBufferField" { - size: Int -} -enum "ValueFlag" { - NAN - MISSING - NEGATIVE_INFINITY - POSITIVE_INFINITY -} -interface "FlaggedBuffer" { - -} -class "FlaggedDoubleBuffer" { - values: DoubleArray - flags: ByteArray -} -class "FloatBuffer" { - array: FloatArray -} -class "IntBuffer" { - array: IntArray -} -class "LongBuffer" { - array: LongArray -} -class "MemoryBuffer" { - memory: Memory - spec: MemorySpec -} -class "MutableMemoryBuffer" { - memory: Memory - spec: MemorySpec -} -class "ShortBuffer" { - array: ShortArray -} -class "ExpressionFieldTest" { - x -} -class "InterpretTest" { - -} -class "SimpleAutoDiffTest" { - x - y - z -} -class "DoubleLUSolverTest" { - -} -class "MatrixTest" { - -} -class "CumulativeKtTest" { - -} -class "BigIntAlgebraTest" { - -} -class "BigIntConstructorTest" { - -} -class "BigIntConversionsTest" { - -} -class "BigIntOperationsTest" { - -} -class "DoubleFieldTest" { - -} -class "NDFieldTest" { - -} -class "NumberNDFieldTest" { - algebra - array1 - array2 -} -class "L2Norm" { - norm() -} -interface "AlgebraicVerifier" { - algebra: A -} -class "FieldVerifier" { - algebra: A - a: T - b: T - c: T - x: Number -} -class "RingVerifier" { - algebra: A - a: T - b: T - c: T - x: Number -} -class "SpaceVerifier" { - algebra: S - a: T - b: T - c: T - x: Number -} -class "JBigIntegerField" { - zero: BigInteger - one: BigIntegernumber() - add() - minus() - multiply() - unaryMinus() -} -abstract "JBigDecimalFieldBase" { - mathContext: MathContext -} -class "JBigDecimalField" { - mathContext: MathContext -} -"ColumnarData" <|--- XYColumnarData -"XYColumnarData" <|--- XYErrorColumnarData -"XYColumnarData" <|--- XYZColumnarData -"Domain" <|--- DoubleDomain -"DoubleDomain" <|--- HyperSquareDomain -"DoubleDomain" <|--- UnconstrainedDomain -"DoubleDomain" <|--- UnivariateDomain -"Expression" <|--- DifferentiableExpression -"DifferentiableExpression" <|--- SpecialDifferentiableExpression -"DifferentiableExpression" <|--- FirstDerivativeExpression -"Algebra" <|--- ExpressionAlgebra -"ExpressionAlgebra" <|--- FunctionalExpressionAlgebra -"FunctionalExpressionAlgebra" <|--- FunctionalExpressionGroup -"Group" <|--- FunctionalExpressionGroup -"FunctionalExpressionGroup" <|--- FunctionalExpressionRing -"Ring" <|--- FunctionalExpressionRing -"FunctionalExpressionRing" <|--- FunctionalExpressionField -"Field" <|--- FunctionalExpressionField -"ScaleOperations" <|--- FunctionalExpressionField -"FunctionalExpressionField" <|--- FunctionalExpressionExtendedField -"ExtendedField" <|--- FunctionalExpressionExtendedField -"MST" <|--- Numeric -"MST" <|--- Unary -"MST" <|--- Binary -"NumericAlgebra" <|--- InnerAlgebra -"NumericAlgebra" <|--- MstNumericAlgebra -"Group" <|--- MstGroup -"NumericAlgebra" <|--- MstGroup -"ScaleOperations" <|--- MstGroup -"Ring" <|--- MstRing -"NumbersAddOperations" <|--- MstRing -"ScaleOperations" <|--- MstRing -"Field" <|--- MstField -"NumbersAddOperations" <|--- MstField -"ScaleOperations" <|--- MstField -"ExtendedField" <|--- MstExtendedField -"NumericAlgebra" <|--- MstExtendedField -"LogicAlgebra" <|--- MstLogicAlgebra -"Field" <|--- SimpleAutoDiffField -"ExpressionAlgebra" <|--- SimpleAutoDiffField -"NumbersAddOperations" <|--- SimpleAutoDiffField -"AutoDiffValue" <|--- AutoDiffVariableWithDerivative -"Symbol" <|--- AutoDiffVariableWithDerivative -"FirstDerivativeExpression" <|--- SimpleAutoDiffExpression -"ExtendedField" <|--- SimpleAutoDiffExtendedField -"ScaleOperations" <|--- SimpleAutoDiffExtendedField -'"" <|--- SimpleAutoDiffExtendedField -"SimpleAutoDiffField" <|--- SimpleAutoDiffExtendedField -"MST" <|--- Symbol -"Symbol" <|--- StringSymbol -"SymbolIndexer" <|--- SimpleSymbolIndexer -"LinearSpace" <|--- BufferedLinearSpace -"LupDecompositionFeature" <|--- LupDecomposition -"DeterminantFeature" <|--- LupDecomposition -"MatrixFeature" <|--- SymmetricMatrixFeature -"StructureFeature" <|--- MatrixFeature -"MatrixFeature" <|--- DiagonalFeature -"DiagonalFeature" <|--- ZeroFeature -"DiagonalFeature" <|--- UnitFeature -"MatrixFeature" <|--- InverseMatrixFeature -"MatrixFeature" <|--- DeterminantFeature -"MatrixFeature" <|--- LFeature -"MatrixFeature" <|--- UFeature -"MatrixFeature" <|--- LUDecompositionFeature -"MatrixFeature" <|--- LupDecompositionFeature -"MatrixFeature" <|--- OrthogonalFeature -"MatrixFeature" <|--- QRDecompositionFeature -"MatrixFeature" <|--- CholeskyDecompositionFeature -"MatrixFeature" <|--- SingularValueDecompositionFeature -'"Matrixbyorigin{ -' -' -' @UnstableKMathAPI -' @Suppress -'overridefungetFeature:F? = -'features.getFeature -' -'overridefuntoString" -'}" <|--- MatrixWrapper -"MatrixFeature" <|--- TransposedFeature -"Matrix" <|--- VirtualMatrix -"Featured" <|--- FeatureSet -"RuntimeException" <|--- ShapeMismatchException -"Group" <|--- GroupND -"AlgebraND" <|--- GroupND -"Ring" <|--- RingND -"GroupND" <|--- RingND -"Field" <|--- FieldND -"RingND" <|--- FieldND -"AlgebraND" <|--- BufferAlgebraND -"GroupND" <|--- BufferedGroupND -"BufferAlgebraND" <|--- BufferedGroupND -"BufferedGroupND" <|--- BufferedRingND -"RingND" <|--- BufferedRingND -"BufferedRingND" <|--- BufferedFieldND -"FieldND" <|--- BufferedFieldND -"StructureND" <|--- BufferND -"MutableStructureND" <|--- MutableBufferND -"BufferND" <|--- MutableBufferND -"BufferedFieldND" <|--- DoubleFieldND -'" -'" <|--- DoubleFieldND -'"NumbersAddOperations" <|--- DoubleFieldND -'" -'" <|--- DoubleFieldND -'"ScaleOperations" <|--- DoubleFieldND -'" -'" <|--- DoubleFieldND -"ExtendedField" <|--- DoubleFieldND -"BufferedRingND" <|--- ShortRingND -'" -'" <|--- ShortRingND -"NumbersAddOperations" <|--- ShortRingND -"StructureND" <|--- Structure1D -"Buffer" <|--- Structure1D -"Structure1D" <|--- MutableStructure1D -"MutableStructureND" <|--- MutableStructure1D -"MutableBuffer" <|--- MutableStructure1D -"Structure1D" <|--- Structure1DWrapper -"MutableStructure1D" <|--- MutableStructure1DWrapper -"Structure1D" <|--- Buffer1DWrapper -"MutableStructure1D" <|--- MutableBuffer1DWrapper -"StructureND" <|--- Structure2D -"Structure2D" <|--- MutableStructure2D -"MutableStructureND" <|--- MutableStructure2D -"Structure2D" <|--- Structure2DWrapper -"MutableStructure2D" <|--- MutableStructure2DWrapper -"Feature" <|--- StructureFeature -"Featured" <|--- StructureND -"StructureND" <|--- MutableStructureND -"Strides" <|--- DefaultStrides -"Algebra" <|--- GroupOperations -"GroupOperations" <|--- Group -"GroupOperations" <|--- RingOperations -"Group" <|--- Ring -"RingOperations" <|--- Ring -"RingOperations" <|--- FieldOperations -"Ring" <|--- Field -"FieldOperations" <|--- Field -"ScaleOperations" <|--- Field -"NumericAlgebra" <|--- Field -"AlgebraElement" <|--- GroupElement -"GroupElement" <|--- RingElement -"RingElement" <|--- FieldElement -"Field" <|--- BigIntField -"NumbersAddOperations" <|--- BigIntField -"ScaleOperations" <|--- BigIntField -"Comparable" <|--- BigInt -"Algebra" <|--- BufferAlgebra -"BufferAlgebra" <|--- BufferField -"Field" <|--- BufferField -"Algebra" <|--- LogicAlgebra -"LogicAlgebra" <|--- BooleanAlgebra -"FieldOperations" <|--- ExtendedFieldOperations -'" -'" <|--- ExtendedFieldOperations -'"TrigonometricOperations" <|--- ExtendedFieldOperations -'" -'" <|--- ExtendedFieldOperations -'"PowerOperations" <|--- ExtendedFieldOperations -'" -'" <|--- ExtendedFieldOperations -"ExponentialOperations" <|--- ExtendedFieldOperations -"ExtendedFieldOperations" <|--- ExtendedField -"Field" <|--- ExtendedField -"NumericAlgebra" <|--- ExtendedField -"ScaleOperations" <|--- ExtendedField -"ExtendedField" <|--- DoubleField -"Norm" <|--- DoubleField -"ScaleOperations" <|--- DoubleField -"ExtendedField" <|--- FloatField -"Norm" <|--- FloatField -"Ring" <|--- IntRing -"Norm" <|--- IntRing -"NumericAlgebra" <|--- IntRing -"Ring" <|--- ShortRing -"Norm" <|--- ShortRing -"NumericAlgebra" <|--- ShortRing -"Ring" <|--- ByteRing -"Norm" <|--- ByteRing -"NumericAlgebra" <|--- ByteRing -"Ring" <|--- LongRing -"Norm" <|--- LongRing -"NumericAlgebra" <|--- LongRing -"Algebra" <|--- NumericAlgebra -"Algebra" <|--- ScaleOperations -"Ring" <|--- NumbersAddOperations -"NumericAlgebra" <|--- NumbersAddOperations -"Algebra" <|--- TrigonometricOperations -"Algebra" <|--- PowerOperations -"Algebra" <|--- ExponentialOperations -"Buffer" <|--- MutableBuffer -"Buffer" <|--- ListBuffer -"MutableBuffer" <|--- MutableListBuffer -"MutableBuffer" <|--- ArrayBuffer -"Buffer" <|--- ReadOnlyBuffer -"Buffer" <|--- VirtualBuffer -"MutableBuffer" <|--- Row -"MutableBuffer" <|--- DoubleBuffer -"ExtendedFieldOperations" <|--- DoubleBufferFieldOperations -"Norm" <|--- DoubleL2Norm -"ExtendedField" <|--- DoubleBufferField -"Norm" <|--- DoubleBufferField -"Buffer" <|--- FlaggedBuffer -"FlaggedBuffer" <|--- FlaggedDoubleBuffer -'" -'" <|--- FlaggedDoubleBuffer -"Buffer" <|--- FlaggedDoubleBuffer -"MutableBuffer" <|--- FloatBuffer -"MutableBuffer" <|--- IntBuffer -"MutableBuffer" <|--- LongBuffer -"Buffer" <|--- MemoryBuffer -"MemoryBuffer" <|--- MutableMemoryBuffer -'" -'" <|--- MutableMemoryBuffer -"MutableBuffer" <|--- MutableMemoryBuffer -"MutableBuffer" <|--- ShortBuffer -"Norm" <|--- L2Norm -"RingVerifier" <|--- FieldVerifier -"SpaceVerifier" <|--- RingVerifier -"AlgebraicVerifier" <|--- SpaceVerifier -"Ring" <|--- JBigIntegerField -"NumericAlgebra" <|--- JBigIntegerField -"Field" <|--- JBigDecimalFieldBase -"PowerOperations" <|--- JBigDecimalFieldBase -"NumericAlgebra" <|--- JBigDecimalFieldBase -"ScaleOperations" <|--- JBigDecimalFieldBase -"JBigDecimalFieldBase" <|--- JBigDecimalField -@enduml \ No newline at end of file diff --git a/docs/expressions.md b/docs/expressions.md index e6250110c..1e05e5340 100644 --- a/docs/expressions.md +++ b/docs/expressions.md @@ -1,21 +1,26 @@ # Expressions -Expressions is a feature, which allows constructing lazily or immediately calculated parametric mathematical expressions. +**Experimental: this API is in early stage and could change any time** + +Expressions is an experimental feature which allows to construct lazily or immediately calculated parametric mathematical +expressions. The potential use-cases for it (so far) are following: -* lazy evaluation (in general simple lambda is better, but there are some border cases); -* automatic differentiation in single-dimension and in multiple dimensions; -* generation of mathematical syntax trees with subsequent code generation for other languages; -* symbolic computations, especially differentiation (and some other actions with `kmath-symja` integration with Symja's `IExpr`—integration, simplification, and more); -* visualization with `kmath-jupyter`. +* Lazy evaluation (in general simple lambda is better, but there are some border cases) -The workhorse of this API is `Expression` interface, which exposes single `operator fun invoke(arguments: Map): T` -method. `ExpressionAlgebra` is used to generate expressions and introduce variables. +* Automatic differentiation in single-dimension and in multiple dimensions + +* Generation of mathematical syntax trees with subsequent code generation for other languages + +* Maybe symbolic computations (needs additional research) + +The workhorse of this API is `Expression` interface which exposes single `operator fun invoke(arguments: Map): T` +method. `ExpressionContext` is used to generate expressions and introduce variables. Currently there are two implementations: * Generic `ExpressionField` in `kmath-core` which allows construction of custom lazy expressions -* Auto-differentiation expression in `kmath-commons` module allows using full power of `DerivativeStructure` +* Auto-differentiation expression in `kmath-commons` module allows to use full power of `DerivativeStructure` from commons-math. **TODO: add example** diff --git a/docs/features.md b/docs/features.md new file mode 100644 index 000000000..1068a4417 --- /dev/null +++ b/docs/features.md @@ -0,0 +1,14 @@ +# Features + +* [Algebra](algebra.md) - [Context-based](contexts.md) operations on different primitives and structures. + +* [NDStructures](nd-structure.md) + +* [Linear algebra](linear.md) - Matrices, operations and linear equations solving. To be moved to separate module. Currently supports basic +api and multiple library back-ends. + +* [Histograms](histograms.md) - Multidimensional histogram calculation and operations. + +* [Expressions](expressions.md) + +* Commons math integration diff --git a/docs/images/KM.svg b/docs/images/KM.svg index 55a4339b1..83af21f35 100644 --- a/docs/images/KM.svg +++ b/docs/images/KM.svg @@ -1,9 +1,4 @@ - - - - - - - - i.toDouble() } - val mat = buildMatrix(10, 10) { i, j -> i.toDouble() + j } +* `MatrixContext` forms a space-like context for 2d-structures. It does not store matrix size and therefore does not implement +`Space` interface (it is impossible to create zero element without knowing the matrix size). - // Addition - vec + vec - mat + mat +## Vector spaces - // Multiplication by scalar - vec * 2.0 - mat * 2.0 - // Dot product - mat dot vec - mat dot mat -} -``` +## Matrix operations -## Backends overview - -### EJML -### Commons Math +## Back-end overview \ No newline at end of file diff --git a/docs/nd-structure.md b/docs/nd-structure.md index 3e9203ec0..ec9b4d521 100644 --- a/docs/nd-structure.md +++ b/docs/nd-structure.md @@ -11,16 +11,16 @@ Let us consider following contexts: ```kotlin // automatically build context most suited for given type. val autoField = NDField.auto(DoubleField, dim, dim) - // specialized nd-field for Double. It works as generic Double field as well. + // specialized nd-field for Double. It works as generic Double field as well val specializedField = NDField.real(dim, dim) //A generic boxing field. It should be used for objects, not primitives. val genericField = NDField.buffered(DoubleField, dim, dim) ``` -Now let us perform several tests and see, which implementation is best suited for each case: +Now let us perform several tests and see which implementation is best suited for each case: ## Test case -To test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0` +In order to test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0` to it `n = 1000` times. ## Specialized @@ -35,8 +35,8 @@ The code to run this looks like: ``` The performance of this code is the best of all tests since it inlines all operations and is specialized for operation with doubles. We will measure everything else relative to this one, so time for this test will be `1x` (real time -on my computer is about 4.5 seconds). The only problem with this approach is that it requires specifying type -from the beginning. Everyone does so anyway, so it is the recommended approach. +on my computer is about 4.5 seconds). The only problem with this approach is that it requires to specify type +from the beginning. Everyone do so anyway, so it is the recommended approach. ## Automatic Let's do the same with automatic field inference: @@ -49,7 +49,7 @@ Let's do the same with automatic field inference: } ``` Ths speed of this operation is approximately the same as for specialized case since `NDField.auto` just -returns the same `RealNDField` in this case. Of course, it is usually better to use specialized method to be sure. +returns the same `RealNDField` in this case. Of course it is usually better to use specialized method to be sure. ## Lazy Lazy field does not produce a structure when asked, instead it generates an empty structure and fills it on-demand @@ -63,7 +63,7 @@ When one calls } } ``` -The result will be calculated almost immediately but the result will be empty. To get the full result +The result will be calculated almost immediately but the result will be empty. In order to get the full result structure one needs to call all its elements. In this case computation overhead will be huge. So this field never should be used if one expects to use the full result structure. Though if one wants only small fraction, it could save a lot of time. @@ -94,7 +94,7 @@ The boxing field produced by } } ``` -is the slowest one, because it requires boxing and unboxing the `double` on each operation. It takes about +obviously is the slowest one, because it requires to box and unbox the `double` on each operation. It takes about `15x` time (**TODO: there seems to be a problem here, it should be slow, but not that slow**). This field should never be used for primitives. @@ -115,14 +115,12 @@ via extension function. Usually it is bad idea to compare the direct numerical operation performance in different languages, but it hard to work completely without frame of reference. In this case, simple numpy code: ```python -import numpy as np - res = np.ones((1000,1000)) for i in range(1000): res = res + 1.0 ``` gives the completion time of about `1.1x`, which means that specialized kotlin code in fact is working faster (I think it is because better memory management). Of course if one writes `res += 1.0`, the performance will be different, -but it would be different case, because numpy overrides `+=` with in-place operations. In-place operations are +but it would be differenc case, because numpy overrides `+=` with in-place operations. In-place operations are available in `kmath` with `MutableNDStructure` but there is no field for it (one can still work with mapping functions). \ No newline at end of file diff --git a/docs/polynomials.md b/docs/polynomials.md deleted file mode 100644 index b255acda1..000000000 --- a/docs/polynomials.md +++ /dev/null @@ -1,172 +0,0 @@ -# Polynomials and Rational Functions - -KMath provides a way to work with uni- and multivariate polynomials and rational functions. It includes full support of arithmetic operations of integers, **constants** (elements of ring polynomials are build over), variables (for certain multivariate implementations), polynomials and rational functions encapsulated in so-called **polynomial space** and **rational function space** and some other utilities such as algebraic differentiation and substitution. - -## Concrete realizations - -There are 3 approaches to represent polynomials: -1. For univariate polynomials one can represent and store polynomial as a list of coefficients for each power of the variable. I.e. polynomial $a_0 + \dots + a_n x^n $ can be represented as a finite sequence $(a_0; \dots; a_n)$. (Compare to sequential definition of polynomials.) -2. For multivariate polynomials one can represent and store polynomial as a matching (in programming it is called "map" or "dictionary", in math it is called [functional relation](https://en.wikipedia.org/wiki/Binary_relation#Special_types_of_binary_relations)) of each "**term signature**" (that describes what variables and in what powers appear in the term) with corresponding coefficient of the term. But there are 2 possible approaches of term signature representation: - 1. One can number all the variables, so term signature can be represented as a sequence describing powers of the variables. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural or zero $d_i $) can be represented as a finite sequence $(d_0; \dots; d_n)$. - 2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of each appeared variable with its power in the term. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural non-zero $d_i $) can be represented as a finite matching $(x_0 \to d_1; \dots; x_n \to d_n)$. - -All that three approaches are implemented by "list", "numbered", and "labeled" versions of polynomials and polynomial spaces respectively. Whereas all rational functions are represented as fractions with corresponding polynomial numerator and denominator, and rational functions' spaces are implemented in the same way as usual field of rational numbers (or more precisely, as any field of fractions over integral domain) should be implemented. - -So here are a bit of details. Let `C` by type of constants. Then: -1. `ListPolynomial`, `ListPolynomialSpace`, `ListRationalFunction` and `ListRationalFunctionSpace` implement the first scenario. `ListPolynomial` stores polynomial $a_0 + \dots + a_n x^n $ as a coefficients list `listOf(a_0, ..., a_n)` (of type `List`). - - They also have variation `ScalableListPolynomialSpace` that replaces former polynomials and implements `ScaleOperations`. -2. `NumberedPolynomial`, `NumberedPolynomialSpace`, `NumberedRationalFunction` and `NumberedRationalFunctionSpace` implement second scenario. `NumberedPolynomial` stores polynomials as structures of type `Map, C>`. Signatures are stored as `List`. To prevent ambiguity signatures should not end with zeros. -3. `LabeledPolynomial`, `LabeledPolynomialSpace`, `LabeledRationalFunction` and `LabeledRationalFunctionSpace` implement third scenario using common `Symbol` as variable type. `LabeledPolynomial` stores polynomials as structures of type `Map, C>`. Signatures are stored as `Map`. To prevent ambiguity each signature should not map any variable to zero. - -### Example: `ListPolynomial` - -For example, polynomial $2 - 3x + x^2 $ (with `Int` coefficients) is represented -```kotlin -val polynomial: ListPolynomial = ListPolynomial(listOf(2, -3, 1)) -// or -val polynomial: ListPolynomial = ListPolynomial(2, -3, 1) -``` - -All algebraic operations can be used in corresponding space: -```kotlin -val computationResult = Int.algebra.listPolynomialSpace { - ListPolynomial(2, -3, 1) + ListPolynomial(0, 6) == ListPolynomial(2, 3, 1) -} - -println(computationResult) // true -``` - -For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). - -### Example: `NumberedPolynomial` - -For example, polynomial $3 + 5 x_1 - 7 x_0^2 x_2 $ (with `Int` coefficients) is represented -```kotlin -val polynomial: NumberedPolynomial = NumberedPolynomial( - mapOf( - listOf() to 3, - listOf(0u, 1u) to 5, - listOf(2u, 0u, 1u) to -7, - ) -) -// or -val polynomial: NumberedPolynomial = NumberedPolynomial( - listOf() to 3, - listOf(0u, 1u) to 5, - listOf(2u, 0u, 1u) to -7, -) -``` - -All algebraic operations can be used in corresponding space: -```kotlin -val computationResult = Int.algebra.numberedPolynomialSpace { - NumberedPolynomial( - listOf() to 3, - listOf(0u, 1u) to 5, - listOf(2u, 0u, 1u) to -7, - ) + NumberedPolynomial( - listOf(0u, 1u) to -5, - listOf(0u, 0u, 0u, 4u) to 4, - ) == NumberedPolynomial( - listOf() to 3, - listOf(0u, 1u) to 0, - listOf(2u, 0u, 1u) to -7, - listOf(0u, 0u, 0u, 4u) to 4, - ) -} - -println(computationResult) // true -``` - -For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). - -### Example: `LabeledPolynomial` - -For example, polynomial $3 + 5 y - 7 x^2 z $ (with `Int` coefficients) is represented -```kotlin -val polynomial: LabeledPolynomial = LabeledPolynomial( - mapOf( - mapOf() to 3, - mapOf(y to 1u) to 5, - mapOf(x to 2u, z to 1u) to -7, - ) -) -// or -val polynomial: LabeledPolynomial = LabeledPolynomial( - mapOf() to 3, - mapOf(y to 1u) to 5, - mapOf(x to 2u, z to 1u) to -7, -) -``` - -All algebraic operations can be used in corresponding space: -```kotlin -val computationResult = Int.algebra.labeledPolynomialSpace { - LabeledPolynomial( - listOf() to 3, - listOf(0u, 1u) to 5, - listOf(2u, 0u, 1u) to -7, - ) + LabeledPolynomial( - listOf(0u, 1u) to -5, - listOf(0u, 0u, 0u, 4u) to 4, - ) == LabeledPolynomial( - listOf() to 3, - listOf(0u, 1u) to 0, - listOf(2u, 0u, 1u) to -7, - listOf(0u, 0u, 0u, 4u) to 4, - ) -} - -println(computationResult) // true -``` - -For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). - -## Abstract entities (interfaces and abstract classes) - -```mermaid -classDiagram - Polynomial <|-- ListPolynomial - Polynomial <|-- NumberedPolynomial - Polynomial <|-- LabeledPolynomial - - RationalFunction <|-- ListRationalFunction - RationalFunction <|-- NumberedRationalFunction - RationalFunction <|-- LabeledRationalFunction - - Ring <|-- PolynomialSpace - PolynomialSpace <|-- MultivariatePolynomialSpace - PolynomialSpace <|-- PolynomialSpaceOverRing - - Ring <|-- RationalFunctionSpace - RationalFunctionSpace <|-- MultivariateRationalFunctionSpace - RationalFunctionSpace <|-- RationalFunctionSpaceOverRing - RationalFunctionSpace <|-- RationalFunctionSpaceOverPolynomialSpace - RationalFunctionSpace <|-- PolynomialSpaceOfFractions - RationalFunctionSpaceOverPolynomialSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace - MultivariateRationalFunctionSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace - MultivariateRationalFunctionSpace <|-- MultivariatePolynomialSpaceOfFractions - PolynomialSpaceOfFractions <|-- MultivariatePolynomialSpaceOfFractions -``` - -There are implemented `Polynomial` and `RationalFunction` interfaces as abstractions of polynomials and rational functions respectively (although, there is not a lot of logic in them) and `PolynomialSpace` and `RationalFunctionSpace` (that implement `Ring` interface) as abstractions of polynomials' and rational functions' spaces respectively. More precisely, that means they allow to declare common logic of interaction with such objects and spaces: -- `Polynomial` does not provide any logic. It is marker interface. -- `RationalFunction` provides numerator and denominator of rational function and destructuring declaration for them. -- `PolynomialSpace` provides all possible arithmetic interactions of integers, constants (of type `C`), and polynomials (of type `P`) like addition, subtraction, multiplication, and some others and common properties like degree of polynomial. -- `RationalFunctionSpace` provides the same as `PolynomialSpace` but also for rational functions: all possible arithmetic interactions of integers, constants (of type `C`), polynomials (of type `P`), and rational functions (of type `R`) like addition, subtraction, multiplication, division (in some cases), and some others and common properties like degree of polynomial. - -Then to add abstraction of similar behaviour with variables (in multivariate case) there are implemented `MultivariatePolynomialSpace` and `MultivariateRationalFunctionSpace`. They just include variables (of type `V`) in the interactions of the entities. - -Also, to remove boilerplates there were provided helping subinterfaces and abstract subclasses: -- `PolynomialSpaceOverRing` allows to replace implementation of interactions of integers and constants with implementations from provided ring over constants (of type `A: Ring`). -- `RationalFunctionSpaceOverRing` — the same but for `RationalFunctionSpace`. -- `RationalFunctionSpaceOverPolynomialSpace` — the same but "the inheritance" includes interactions with polynomials from provided `PolynomialSpace`. -- `PolynomialSpaceOfFractions` is actually abstract subclass of `RationalFunctionSpace` that implements all fractions boilerplates with provided (`protected`) constructor of rational functions by polynomial numerator and denominator. -- `MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace` and `MultivariatePolynomialSpaceOfFractions` — the same stories of operators inheritance and fractions boilerplates respectively but in multivariate case. - -## Utilities - -For all kinds of polynomials there are provided (implementation details depend on kind of polynomials) such common utilities as: -1. differentiation and anti-differentiation, -2. substitution, invocation and functional representation. \ No newline at end of file diff --git a/docs/readme.md b/docs/readme.md deleted file mode 100644 index 2953b7113..000000000 --- a/docs/readme.md +++ /dev/null @@ -1,14 +0,0 @@ -# Documentation - -* [Algebra](algebra.md): [context-based](contexts.md) operations on different primitives and structures. - -* [NDStructures](nd-structure.md) - -* [Linear algebra](linear.md): matrices, operations and linear equations solving. To be moved to separate module. - Currently, supports basic API and multiple library back-ends. - -* [Histograms](histograms.md): multidimensional histogram calculation and operations. - -* [Expressions](expressions.md) - -* Commons math integration diff --git a/docs/templates/ARTIFACT-TEMPLATE.md b/docs/templates/ARTIFACT-TEMPLATE.md index a3e47e693..01d9c51da 100644 --- a/docs/templates/ARTIFACT-TEMPLATE.md +++ b/docs/templates/ARTIFACT-TEMPLATE.md @@ -3,12 +3,11 @@ The Maven coordinates of this project are `${group}:${name}:${version}`. **Gradle:** -```groovy +```gradle repositories { maven { url 'https://repo.kotlin.link' } - mavenCentral() - // development and snapshot versions - maven { url 'https://maven.pkg.jetbrains.space/spc/p/sci/dev' } + maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap } dependencies { @@ -19,9 +18,8 @@ dependencies { ```kotlin repositories { maven("https://repo.kotlin.link") - mavenCentral() - // development and snapshot versions - maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev") + maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap + maven("https://dl.bintray.com/hotkeytlt/maven") // required for a } dependencies { diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index d7d5a806d..99951b4d6 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -1,17 +1,17 @@ [![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) -![Gradle build](https://github.com/SciProgCentre/kmath/workflows/Gradle%20build/badge.svg) +![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) -[![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) +[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) # KMath -Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based -analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior -architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like -experience could be achieved with [kmath-for-real](/kmath-for-real) extension module. +Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to +Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture +designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could +be achieved with [kmath-for-real](/kmath-for-real) extension module. -[Documentation site (**WIP**)](https://SciProgCentre.github.io/kmath/) +[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) ## Publications and talks @@ -21,67 +21,87 @@ experience could be achieved with [kmath-for-real](/kmath-for-real) extension mo # Goal -* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native) - . +* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native). * Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide bindings and wrappers with those abstractions for popular optimized platform libraries. ## Non-goals -* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API. +* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API. * Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. -* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like - for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better - experience for those, who want to work with specific types. +* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like +for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better +experience for those, who want to work with specific types. ## Features and stability -KMath is a modular library. Different modules provide different features with different API stability guarantees. All -core modules are released with the same version, but with different API change policy. The features are described in -module definitions below. The module stability could have the following levels: +KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels: -* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could - break any moment. You can still use it, but be sure to fix the specific version. -* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked - with `@UnstableKMathAPI` or other stability warning annotations. -* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor - versions, but not in patch versions. API is protected - with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. +* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. +* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations. +* **DEVELOPMENT**. API breaking genrally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## Modules -${modules} +$modules ## Multi-platform support -KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the -[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features -are delegated to platform-specific implementations even if they could be provided in the common module for performance -reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and +KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the +[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features +are delegated to platform-specific implementations even if they could be provided in the common module for performance +reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and feedback are also welcome. ## Performance -Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both -performance and flexibility. +Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve +both performance and flexibility. -We expect to focus on creating convenient universal API first and then work on increasing performance for specific -cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized -native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. +We expect to focus on creating convenient universal API first and then work on increasing performance for specific +cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized +native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be +better than SciPy. ## Requirements -KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for -execution to get better performance. +KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance. ### Repositories -Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) -repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of -[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could -be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: +Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of +[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: ```kotlin repositories { @@ -98,7 +118,7 @@ Gradle `6.0+` is required for multiplatform artifacts. ## Contributing -The project requires a lot of additional work. The most important thing we need is a feedback about what features are -required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues -marked with -[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. \ No newline at end of file +The project requires a lot of additional work. The most important thing we need is a feedback about what features are +required the most. Feel free to create feature requests. We are also welcome to code contributions, +especially in issues marked with +[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index d4e1c5289..000000000 --- a/examples/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Module examples - - - diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 7f2abc852..98d7b7073 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -1,17 +1,38 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import ru.mipt.npm.gradle.Maturity plugins { kotlin("jvm") + kotlin("plugin.allopen") + id("org.jetbrains.kotlinx.benchmark") } +allOpen.annotation("org.openjdk.jmh.annotations.State") +sourceSets.register("benchmarks") + repositories { - mavenCentral() + jcenter() maven("https://repo.kotlin.link") - maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers") + maven("https://clojars.org/repo") + maven("https://dl.bintray.com/egor-bogomolov/astminer/") + maven("https://dl.bintray.com/hotkeytlt/maven") + maven("https://dl.bintray.com/kotlin/kotlin-eap") + maven("https://dl.bintray.com/kotlin/kotlinx") + maven("https://dl.bintray.com/mipt-npm/dev") + maven("https://dl.bintray.com/mipt-npm/kscience") + maven("https://jitpack.io") + maven{ + setUrl("http://logicrunch.research.it.uu.se/maven/") + isAllowInsecureProtocol = true + } + mavenCentral() } -val multikVersion: String by rootProject.extra - dependencies { implementation(project(":kmath-ast")) implementation(project(":kmath-kotlingrad")) @@ -19,25 +40,15 @@ dependencies { implementation(project(":kmath-coroutines")) implementation(project(":kmath-commons")) implementation(project(":kmath-complex")) - implementation(project(":kmath-functions")) - implementation(project(":kmath-optimization")) implementation(project(":kmath-stat")) implementation(project(":kmath-viktor")) implementation(project(":kmath-dimensions")) implementation(project(":kmath-ejml")) implementation(project(":kmath-nd4j")) - implementation(project(":kmath-tensors")) - implementation(project(":kmath-symja")) + implementation(project(":kmath-for-real")) - //jafama - implementation(project(":kmath-jafama")) - //multik - implementation(project(":kmath-multik")) - implementation("org.jetbrains.kotlinx:multik-default:$multikVersion") - - //datetime - implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") + implementation("org.deeplearning4j:deeplearning4j-core:1.0.0-beta7") implementation("org.nd4j:nd4j-native:1.0.0-beta7") // uncomment if your system supports AVX2 @@ -50,28 +61,79 @@ dependencies { // } else implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - implementation("org.slf4j:slf4j-simple:1.7.32") + implementation("org.jetbrains.kotlinx:kotlinx-io:0.2.0-npm-dev-11") + implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.0") + implementation("org.slf4j:slf4j-simple:1.7.30") + // plotting - implementation("space.kscience:plotlykt-server:0.5.0") + implementation("kscience.plotlykt:plotlykt-server:0.3.1-dev") + + "benchmarksImplementation"("org.jetbrains.kotlinx:kotlinx.benchmark.runtime-jvm:0.2.0-dev-20") + "benchmarksImplementation"(sourceSets.main.get().output + sourceSets.main.get().runtimeClasspath) } -kotlin { - jvmToolchain(11) - sourceSets.all { - languageSettings { - optIn("kotlin.contracts.ExperimentalContracts") - optIn("kotlin.ExperimentalUnsignedTypes") - optIn("space.kscience.kmath.UnstableKMathAPI") - } +// Configure benchmark +benchmark { + // Setup configurations + targets.register("benchmarks") + // This one matches sourceSet name above + + configurations.register("buffer") { + warmups = 1 // number of warmup iterations + iterations = 3 // number of iterations + iterationTime = 500 // time in seconds per iteration + iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds + include("BufferBenchmark") + } + + configurations.register("dot") { + warmups = 1 // number of warmup iterations + iterations = 3 // number of iterations + iterationTime = 500 // time in seconds per iteration + iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds + include("DotBenchmark") + } + + configurations.register("expressions") { + warmups = 1 // number of warmup iterations + iterations = 3 // number of iterations + iterationTime = 500 // time in seconds per iteration + iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds + include("ExpressionsInterpretersBenchmark") + } + + configurations.register("matrixInverse") { + warmups = 1 // number of warmup iterations + iterations = 3 // number of iterations + iterationTime = 500 // time in seconds per iteration + iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds + include("MatrixInverseBenchmark") + } + + configurations.register("bigInt") { + warmups = 1 // number of warmup iterations + iterations = 3 // number of iterations + iterationTime = 500 // time in seconds per iteration + iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds + include("BigIntBenchmark") } } -tasks.withType { - kotlinOptions { - freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" +kotlin.sourceSets.all { + with(languageSettings) { + useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") + useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") + useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") + } +} + +tasks.withType { + kotlinOptions{ + jvmTarget = "11" + freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" } } readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + maturity = Maturity.EXPERIMENTAL } diff --git a/examples/notebooks/Naive classifier.ipynb b/examples/notebooks/Naive classifier.ipynb deleted file mode 100644 index 937f5b6c6..000000000 --- a/examples/notebooks/Naive classifier.ipynb +++ /dev/null @@ -1,418 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "source": [ - "%use kmath(0.3.1-dev-5)\n", - "%use plotly(0.5.0)\n", - "@file:DependsOn(\"space.kscience:kmath-commons:0.3.1-dev-5\")" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "lQbSB87rNAn9lV6poArVWW", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "code", - "source": [ - "//Uncomment to work in Jupyter classic or DataLore\n", - "//Plotly.jupyter.notebook()" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "0UP158hfccGgjQtHz0wAi6", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "markdown", - "source": [ - "# The model\n", - "\n", - "Defining the input data format, the statistic abstraction and the statistic implementation based on a weighted sum of elements." - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "source": [ - "class XYValues(val xValues: DoubleArray, val yValues: DoubleArray) {\n", - " init {\n", - " require(xValues.size == yValues.size)\n", - " }\n", - "}\n", - "\n", - "fun interface XYStatistic {\n", - " operator fun invoke(values: XYValues): Double\n", - "}\n", - "\n", - "class ConvolutionalXYStatistic(val weights: DoubleArray) : XYStatistic {\n", - " override fun invoke(values: XYValues): Double {\n", - " require(weights.size == values.yValues.size)\n", - " val norm = values.yValues.sum()\n", - " return values.yValues.zip(weights) { value, weight -> value * weight }.sum()/norm\n", - " }\n", - "}" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "Zhgz1Ui91PWz0meJiQpHol", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "markdown", - "source": [ - "# Generator\n", - "Generate sample data for parabolas and hyperbolas" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "fun generateParabolas(xValues: DoubleArray, a: Double, b: Double, c: Double): XYValues {\n", - " val yValues = xValues.map { x -> a * x * x + b * x + c }.toDoubleArray()\n", - " return XYValues(xValues, yValues)\n", - "}\n", - "\n", - "fun generateHyperbols(xValues: DoubleArray, gamma: Double, x0: Double, y0: Double): XYValues {\n", - " val yValues = xValues.map { x -> y0 + gamma / (x - x0) }.toDoubleArray()\n", - " return XYValues(xValues, yValues)\n", - "}" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "source": [ - "val xValues = (1.0..10.0).step(1.0).toDoubleArray()\n", - "\n", - "val xy = generateHyperbols(xValues, 1.0, 0.0, 0.0)\n", - "\n", - "Plotly.plot {\n", - " scatter {\n", - " this.x.doubles = xValues\n", - " this.y.doubles = xy.yValues\n", - " }\n", - "}" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "ZE2atNvFzQsCvpAF8KK4ch", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Create a default statistic with uniform weights" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "source": [ - "val statistic = ConvolutionalXYStatistic(DoubleArray(xValues.size){1.0})\n", - "statistic(xy)" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "EA5HaydTddRKYrtAUwd29h", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "code", - "source": [ - "import kotlin.random.Random\n", - "\n", - "val random = Random(1288)\n", - "\n", - "val parabolas = buildList{\n", - " repeat(500){\n", - " add(\n", - " generateParabolas(\n", - " xValues, \n", - " random.nextDouble(), \n", - " random.nextDouble(), \n", - " random.nextDouble()\n", - " )\n", - " )\n", - " }\n", - "}\n", - "\n", - "val hyperbolas: List = buildList{\n", - " repeat(500){\n", - " add(\n", - " generateHyperbols(\n", - " xValues, \n", - " random.nextDouble()*10, \n", - " random.nextDouble(), \n", - " random.nextDouble()\n", - " )\n", - " )\n", - " }\n", - "}" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "t5t6IYmD7Q1ykeo9uijFfQ", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "code", - "source": [ - "Plotly.plot { \n", - " scatter { \n", - " x.doubles = xValues\n", - " y.doubles = parabolas[257].yValues\n", - " }\n", - " scatter { \n", - " x.doubles = xValues\n", - " y.doubles = hyperbolas[252].yValues\n", - " }\n", - " }" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "oXB8lmju7YVYjMRXITKnhO", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "code", - "source": [ - "Plotly.plot { \n", - " histogram { \n", - " name = \"parabolae\"\n", - " x.numbers = parabolas.map { statistic(it) }\n", - " }\n", - " histogram { \n", - " name = \"hyperbolae\"\n", - " x.numbers = hyperbolas.map { statistic(it) }\n", - " }\n", - "}" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "8EIIecUZrt2NNrOkhxG5P0", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "code", - "source": [ - "val lossFunction: (XYStatistic) -> Double = { statistic ->\n", - " - abs(parabolas.sumOf { statistic(it) } - hyperbolas.sumOf { statistic(it) })\n", - "}" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "h7UmglJW5zXkAfKHK40oIL", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Using commons-math optimizer to optimize weights" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "source": [ - "import org.apache.commons.math3.optim.*\n", - "import org.apache.commons.math3.optim.nonlinear.scalar.*\n", - "import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.*\n", - "\n", - "val optimizer = SimplexOptimizer(1e-1, Double.MAX_VALUE)\n", - "\n", - "val result = optimizer.optimize(\n", - " ObjectiveFunction { point ->\n", - " lossFunction(ConvolutionalXYStatistic(point))\n", - " },\n", - " NelderMeadSimplex(xValues.size),\n", - " InitialGuess(DoubleArray(xValues.size){ 1.0 }),\n", - " GoalType.MINIMIZE,\n", - " MaxEval(100000)\n", - ")" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "0EG3K4aCUciMlgGQKPvJ57", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Print resulting weights of optimization" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "source": [ - "result.point" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "LelUlY0ZSlJEO9yC6SLk5B", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "code", - "source": [ - "Plotly.plot { \n", - " scatter { \n", - " y.doubles = result.point\n", - " }\n", - "}" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "AuFOq5t9KpOIkGrOLsVXNf", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "markdown", - "source": [ - "# The resulting statistic distribution" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "source": [ - "val resultStatistic = ConvolutionalXYStatistic(result.point)\n", - "Plotly.plot { \n", - " histogram { \n", - " name = \"parabolae\"\n", - " x.numbers = parabolas.map { resultStatistic(it) }\n", - " }\n", - " histogram { \n", - " name = \"hyperbolae\"\n", - " x.numbers = hyperbolas.map { resultStatistic(it) }\n", - " }\n", - "}" - ], - "execution_count": null, - "outputs": [], - "metadata": { - "datalore": { - "node_id": "zvmq42DRdM5mZ3SpzviHwI", - "type": "CODE", - "hide_input_from_viewers": false, - "hide_output_from_viewers": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [], - "metadata": { - "collapsed": false - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Kotlin", - "language": "kotlin", - "name": "kotlin" - }, - "datalore": { - "version": 1, - "computation_mode": "JUPYTER", - "package_manager": "pip", - "base_environment": "default", - "packages": [] - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt similarity index 96% rename from benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt rename to examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt index abfc8cbf2..ff933997f 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt new file mode 100644 index 000000000..672efd5c2 --- /dev/null +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Blackhole +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State +import space.kscience.kmath.operations.BigIntField +import space.kscience.kmath.operations.JBigIntegerField +import space.kscience.kmath.operations.invoke + +@State(Scope.Benchmark) +internal class BigIntBenchmark { + + val kmNumber = BigIntField.number(Int.MAX_VALUE) + val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE) + + @Benchmark + fun kmAdd(blackhole: Blackhole) = BigIntField { + blackhole.consume(kmNumber + kmNumber + kmNumber) + } + + @Benchmark + fun jvmAdd(blackhole: Blackhole) = JBigIntegerField { + blackhole.consume(jvmNumber + jvmNumber + jvmNumber) + } + + @Benchmark + fun kmMultiply(blackhole: Blackhole) = BigIntField { + blackhole.consume(kmNumber * kmNumber * kmNumber) + } + + @Benchmark + fun jvmMultiply(blackhole: Blackhole) = JBigIntegerField { + blackhole.consume(jvmNumber * jvmNumber * jvmNumber) + } +} \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt new file mode 100644 index 000000000..39819d407 --- /dev/null +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State +import space.kscience.kmath.complex.Complex +import space.kscience.kmath.complex.complex +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.MutableBuffer + +@State(Scope.Benchmark) +internal class BufferBenchmark { + @Benchmark + fun genericDoubleBufferReadWrite() { + val buffer = DoubleBuffer(size) { it.toDouble() } + + (0 until size).forEach { + buffer[it] + } + } + + @Benchmark + fun complexBufferReadWrite() { + val buffer = MutableBuffer.complex(size / 2) { Complex(it.toDouble(), -it.toDouble()) } + + (0 until size / 2).forEach { + buffer[it] + } + } + + private companion object { + private const val size = 100 + } +} diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt new file mode 100644 index 000000000..23e73cb5f --- /dev/null +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State +import space.kscience.kmath.commons.linear.CMLinearSpace +import space.kscience.kmath.ejml.EjmlLinearSpace +import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.linear.invoke +import space.kscience.kmath.operations.DoubleField +import kotlin.random.Random + +@State(Scope.Benchmark) +internal class DotBenchmark { + companion object { + val random = Random(12224) + const val dim = 1000 + + //creating invertible matrix + val matrix1 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + val matrix2 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + + val cmMatrix1 = CMLinearSpace { matrix1.toCM() } + val cmMatrix2 = CMLinearSpace { matrix2.toCM() } + + val ejmlMatrix1 = EjmlLinearSpace { matrix1.toEjml() } + val ejmlMatrix2 = EjmlLinearSpace { matrix2.toEjml() } + } + + @Benchmark + fun cmDot(blackhole: Blackhole) { + CMLinearSpace.run { + blackhole.consume(cmMatrix1 dot cmMatrix2) + } + } + + @Benchmark + fun ejmlDot(blackhole: Blackhole) { + EjmlLinearSpace { + blackhole.consume(ejmlMatrix1 dot ejmlMatrix2) + } + } + + @Benchmark + fun ejmlDotWithConversion(blackhole: Blackhole) { + EjmlLinearSpace { + blackhole.consume(matrix1 dot matrix2) + } + } + + @Benchmark + fun bufferedDot(blackhole: Blackhole) { + LinearSpace.auto(DoubleField).invoke { + blackhole.consume(matrix1 dot matrix2) + } + } + + @Benchmark + fun realDot(blackhole: Blackhole) { + LinearSpace.real { + blackhole.consume(matrix1 dot matrix2) + } + } +} diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt new file mode 100644 index 000000000..d6fde8398 --- /dev/null +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State +import space.kscience.kmath.asm.compileToExpression +import space.kscience.kmath.expressions.* +import space.kscience.kmath.misc.symbol +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.bindSymbol +import space.kscience.kmath.operations.invoke +import kotlin.random.Random + +@State(Scope.Benchmark) +internal class ExpressionsInterpretersBenchmark { + @Benchmark + fun functionalExpression(blackhole: Blackhole) { + val expr = algebra.expressionInField { + val x = bindSymbol(x) + x * const(2.0) + const(2.0) / x - const(16.0) + } + + invokeAndSum(expr, blackhole) + } + + @Benchmark + fun mstExpression(blackhole: Blackhole) { + val expr = MstField { + val x = bindSymbol(x) + x * 2.0 + number(2.0) / x - 16.0 + }.toExpression(algebra) + + invokeAndSum(expr, blackhole) + } + + @Benchmark + fun asmExpression(blackhole: Blackhole) { + val expr = MstField { + val x = bindSymbol(x) + x * 2.0 + number(2.0) / x - 16.0 + }.compileToExpression(algebra) + + invokeAndSum(expr, blackhole) + } + + @Benchmark + fun rawExpression(blackhole: Blackhole) { + val expr = Expression { args -> + val x = args.getValue(x) + x * 2.0 + 2.0 / x - 16.0 + } + + invokeAndSum(expr, blackhole) + } + + private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { + val random = Random(0) + var sum = 0.0 + + repeat(1000000) { + sum += expr(x to random.nextDouble()) + } + + blackhole.consume(sum) + } + + private companion object { + private val algebra = DoubleField + private val x by symbol + } +} diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt new file mode 100644 index 000000000..d1803e389 --- /dev/null +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State +import space.kscience.kmath.commons.linear.CMLinearSpace +import space.kscience.kmath.commons.linear.inverse +import space.kscience.kmath.ejml.EjmlLinearSpace +import space.kscience.kmath.ejml.inverse +import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.linear.inverseWithLup +import space.kscience.kmath.linear.invoke +import kotlin.random.Random + +@State(Scope.Benchmark) +internal class MatrixInverseBenchmark { + companion object { + val random = Random(1224) + const val dim = 100 + + private val space = LinearSpace.real + + //creating invertible matrix + val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 } + val matrix = space { l dot u } + } + + @Benchmark + fun kmathLupInversion(blackhole: Blackhole) { + blackhole.consume(LinearSpace.real.inverseWithLup(matrix)) + } + + @Benchmark + fun cmLUPInversion(blackhole: Blackhole) { + with(CMLinearSpace) { + blackhole.consume(inverse(matrix)) + } + } + + @Benchmark + fun ejmlInverse(blackhole: Blackhole) { + with(EjmlLinearSpace) { + blackhole.consume(inverse(matrix)) + } + } +} diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt new file mode 100644 index 000000000..5e0c6735f --- /dev/null +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State +import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.structures.Buffer + +@State(Scope.Benchmark) +internal class NDFieldBenchmark { + @Benchmark + fun autoFieldAdd(blackhole: Blackhole) { + with(autoField) { + var res: StructureND = one + repeat(n) { res += one } + blackhole.consume(res) + } + } + + @Benchmark + fun specializedFieldAdd(blackhole: Blackhole) { + with(specializedField) { + var res: StructureND = one + repeat(n) { res += 1.0 } + blackhole.consume(res) + } + } + + + @Benchmark + fun boxingFieldAdd(blackhole: Blackhole) { + with(genericField) { + var res: StructureND = one + repeat(n) { res += 1.0 } + blackhole.consume(res) + } + } + + private companion object { + private const val dim = 1000 + private const val n = 100 + private val autoField = AlgebraND.auto(DoubleField, dim, dim) + private val specializedField = AlgebraND.real(dim, dim) + private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) + } +} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt similarity index 60% rename from benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt rename to examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index 90f3cb765..d2359a791 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,20 +10,28 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.ShapeND +import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.one +import space.kscience.kmath.nd.auto +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.viktor.ViktorFieldND +import space.kscience.kmath.viktor.ViktorNDField @State(Scope.Benchmark) internal class ViktorBenchmark { + @Benchmark + fun automaticFieldAddition(blackhole: Blackhole) { + with(autoField) { + var res: StructureND = one + repeat(n) { res += 1.0 } + blackhole.consume(res) + } + } @Benchmark - fun doubleFieldAddition(blackhole: Blackhole) { - with(doubleField) { - var res: StructureND = one(shape) + fun realFieldAddition(blackhole: Blackhole) { + with(realField) { + var res: StructureND = one repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -32,7 +40,7 @@ internal class ViktorBenchmark { @Benchmark fun viktorFieldAddition(blackhole: Blackhole) { with(viktorField) { - var res = one(shape) + var res = one repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -49,10 +57,10 @@ internal class ViktorBenchmark { private companion object { private const val dim = 1000 private const val n = 100 - private val shape = ShapeND(dim, dim) // automatically build context most suited for given type. - private val doubleField = DoubleField.ndAlgebra - private val viktorField = ViktorFieldND(dim, dim) + private val autoField = AlgebraND.auto(DoubleField, dim, dim) + private val realField = AlgebraND.real(dim, dim) + private val viktorField = ViktorNDField(dim, dim) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt similarity index 72% rename from benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt rename to examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index 4ec4605ed..eac8634f5 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,9 +10,9 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.one +import space.kscience.kmath.nd.AlgebraND +import space.kscience.kmath.nd.auto +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.viktor.ViktorFieldND @@ -20,9 +20,9 @@ import space.kscience.kmath.viktor.ViktorFieldND internal class ViktorLogBenchmark { @Benchmark fun realFieldLog(blackhole: Blackhole) { - with(doubleField) { - val fortyTwo = structureND(shape) { 42.0 } - var res = one(shape) + with(realNdField) { + val fortyTwo = produce { 42.0 } + var res = one repeat(n) { res = ln(fortyTwo) } blackhole.consume(res) } @@ -31,7 +31,7 @@ internal class ViktorLogBenchmark { @Benchmark fun viktorFieldLog(blackhole: Blackhole) { with(viktorField) { - val fortyTwo = structureND(shape) { 42.0 } + val fortyTwo = produce { 42.0 } var res = one repeat(n) { res = ln(fortyTwo) } blackhole.consume(res) @@ -49,10 +49,10 @@ internal class ViktorLogBenchmark { private companion object { private const val dim = 1000 private const val n = 100 - private val shape = ShapeND(dim, dim) // automatically build context most suited for given type. - private val doubleField = DoubleField.ndAlgebra - private val viktorField = ViktorFieldND(dim, dim) + private val autoField = AlgebraND.auto(DoubleField, dim, dim) + private val realNdField = AlgebraND.real(dim, dim) + private val viktorField = ViktorFieldND(intArrayOf(dim, dim)) } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt index e85bab8d8..e16769464 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,7 +10,7 @@ import space.kscience.kmath.ast.rendering.LatexSyntaxRenderer import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer import space.kscience.kmath.ast.rendering.renderWithStringBuilder -fun main() { +public fun main() { val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath() val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst) println("MathSyntax:") diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt index cacb6683e..918134e04 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt @@ -1,26 +1,24 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast -import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.expressions.MstExtendedField -import space.kscience.kmath.expressions.Symbol.Companion.x +import space.kscience.kmath.expressions.MstField +import space.kscience.kmath.expressions.interpret +import space.kscience.kmath.misc.Symbol.Companion.x import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke fun main() { - val expr = MstExtendedField { - x * 2.0 + number(2.0) / x - number(16.0) + asinh(x) / sin(x) - }.compileToExpression(DoubleField) - - val m = DoubleArray(expr.indexer.symbols.size) - val xIdx = expr.indexer.indexOf(x) + val expr = MstField { + val x = bindSymbol(x) + x * 2.0 + number(2.0) / x - 16.0 + } repeat(10000000) { - m[xIdx] = 1.0 - expr(m) + expr.interpret(DoubleField, x to 1.0) } -} +} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt index b443e639d..4a31f33a3 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt @@ -1,27 +1,29 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast +import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.expressions.derivative import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.toExpression -import space.kscience.kmath.kotlingrad.toKotlingradExpression +import space.kscience.kmath.kotlingrad.toDiffExpression +import space.kscience.kmath.misc.symbol import space.kscience.kmath.operations.DoubleField /** - * In this example, *x2 − 4 x − 44* function is differentiated with Kotlin∇, and the - * derivation result is compared with valid derivative in a certain point. + * In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with + * valid derivative. */ fun main() { - val actualDerivative = "x^2-4*x-44" - .parseMath() - .toKotlingradExpression(DoubleField) + val x by symbol + + val actualDerivative = "x^2-4*x-44".parseMath() + .toDiffExpression(DoubleField) .derivative(x) - val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField) - check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0)) + + val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField) + assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0)) } diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt deleted file mode 100644 index 92ee1781b..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.derivative -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.expressions.toExpression -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.symja.toSymjaExpression - -/** - * In this example, *x2 − 4 x − 44* function is differentiated with Symja, and the - * derivation result is compared with valid derivative in a certain point. - */ -fun main() { - val actualDerivative = "x^2-4*x-44" - .parseMath() - .toSymjaExpression(DoubleField) - .derivative(x) - - val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField) - check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0)) -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt similarity index 63% rename from examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt rename to examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt index 258ed0c84..be4dc461b 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt @@ -1,34 +1,32 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.fit +package space.kscience.kmath.commons.fit import kotlinx.html.br import kotlinx.html.h3 -import space.kscience.kmath.commons.optimization.CMOptimizer +import kscience.plotly.* +import kscience.plotly.models.ScatterMode +import kscience.plotly.models.TraceValues +import space.kscience.kmath.commons.optimization.chiSquared +import space.kscience.kmath.commons.optimization.minimize import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.expressions.autodiff -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.operations.asIterable -import space.kscience.kmath.operations.toList -import space.kscience.kmath.optimization.FunctionOptimizationTarget -import space.kscience.kmath.optimization.optimizeWith -import space.kscience.kmath.optimization.resultPoint -import space.kscience.kmath.optimization.resultValue -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.misc.symbol +import space.kscience.kmath.optimization.FunctionOptimization +import space.kscience.kmath.optimization.OptimizationResult import space.kscience.kmath.real.DoubleVector import space.kscience.kmath.real.map import space.kscience.kmath.real.step -import space.kscience.kmath.stat.chiSquaredExpression -import space.kscience.plotly.* -import space.kscience.plotly.models.ScatterMode -import space.kscience.plotly.models.TraceValues +import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.structures.asIterable +import space.kscience.kmath.structures.toList import kotlin.math.pow import kotlin.math.sqrt -// Forward declaration of symbols that will be used in expressions. +//Forward declaration of symbols that will be used in expressions. +// This declaration is required for private val a by symbol private val b by symbol private val c by symbol @@ -45,7 +43,7 @@ operator fun TraceValues.invoke(vector: DoubleVector) { */ suspend fun main() { //A generator for a normally distributed values - val generator = NormalDistribution(0.0, 1.0) + val generator = NormalDistribution(2.0, 7.0) //A chain/flow of random values with the given seed val chain = generator.sample(RandomGenerator.default(112667)) @@ -56,7 +54,7 @@ suspend fun main() { //Perform an operation on each x value (much more effective, than numpy) - val y = x.map { it -> + val y = x.map { val value = it.pow(2) + it + 1 value + chain.next() * sqrt(value) } @@ -67,21 +65,17 @@ suspend fun main() { val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma) // compute differentiable chi^2 sum for given model ax^2 + bx + c - val chi2 = Double.autodiff.chiSquaredExpression(x, y, yErr) { arg -> + val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 -> //bind variables to autodiff context val a = bindSymbol(a) val b = bindSymbol(b) //Include default value for c if it is not provided as a parameter val c = bindSymbolOrNull(c) ?: one - a * arg.pow(2) + b * arg + c + a * x1.pow(2) + b * x1 + c } //minimize the chi^2 in given starting point. Derivatives are not required, they are already included. - val result = chi2.optimizeWith( - CMOptimizer, - mapOf(a to 1.5, b to 0.9, c to 1.0), - FunctionOptimizationTarget.MINIMIZE - ) + val result: OptimizationResult = chi2.minimize(a to 1.5, b to 0.9, c to 1.0) //display a page with plot and numerical results val page = Plotly.page { @@ -98,7 +92,7 @@ suspend fun main() { scatter { mode = ScatterMode.lines x(x) - y(x.map { result.resultPoint[a]!! * it.pow(2) + result.resultPoint[b]!! * it + 1 }) + y(x.map { result.point[a]!! * it.pow(2) + result.point[b]!! * it + 1 }) name = "fit" } } @@ -107,7 +101,7 @@ suspend fun main() { +"Fit result: $result" } h3 { - +"Chi2/dof = ${result.resultValue / (x.size - 3)}" + +"Chi2/dof = ${result.value / (x.size - 3)}" } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt b/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt deleted file mode 100644 index 863d6be7a..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.UnstableKMathAPI -// Only kmath-core is needed. - -// Let's declare some variables -val x by symbol -val y by symbol -val z by symbol - -@OptIn(UnstableKMathAPI::class) -fun main() { - // Let's define some random expression. - val someExpression = Double.autodiff.differentiate { - // We bind variables `x` and `y` to the builder scope, - val x = bindSymbol(x) - val y = bindSymbol(y) - - // Then we use the bindings to define expression `xy + x + y - 1` - x * y + x + y - 1 - } - - // Then we can evaluate it at any point ((-1, -1) in the case): - println(someExpression(x to -1.0, y to -1.0)) - // >>> -2.0 - - // We can also construct its partial derivatives: - val dxExpression = someExpression.derivative(x) // ∂/∂x. Must be `y+1` - val dyExpression = someExpression.derivative(y) // ∂/∂y. Must be `x+1` - val dxdxExpression = someExpression.derivative(x, x) // ∂^2/∂x^2. Must be `0` - - // We can evaluate them as well - println(dxExpression(x to 57.0, y to 6.0)) - // >>> 7.0 - println(dyExpression(x to -1.0, y to 179.0)) - // >>> 0.0 - println(dxdxExpression(x to 239.0, y to 30.0)) - // >>> 0.0 - - // You can also provide extra arguments that obviously won't affect the result: - println(dxExpression(x to 57.0, y to 6.0, z to 42.0)) - // >>> 7.0 - println(dyExpression(x to -1.0, y to 179.0, z to 0.0)) - // >>> 0.0 - println(dxdxExpression(x to 239.0, y to 30.0, z to 100_000.0)) - // >>> 0.0 - - // But in case you forgot to specify bound symbol's value, exception is thrown: - println( runCatching { someExpression(z to 4.0) } ) - // >>> Failure(java.lang.IllegalStateException: Symbol 'x' is not supported in ...) - - // The reason is that the expression is evaluated lazily, - // and each `bindSymbol` operation actually substitutes the provided symbol with the corresponding value. - - // For example, let there be an expression - val simpleExpression = Double.autodiff.differentiate { - val x = bindSymbol(x) - x pow 2 - } - // When you evaluate it via - simpleExpression(x to 1.0, y to 57.0, z to 179.0) - // lambda above has the context of map `{x: 1.0, y: 57.0, z: 179.0}`. - // When x is bound, you can think of it as substitution `x -> 1.0`. - // Other values are unused which does not make any problem to us. - // But in the case the corresponding value is not provided, - // we cannot bind the variable. Thus, exception is thrown. - - // There is also a function `bindSymbolOrNull` that fixes the problem: - val fixedExpression = Double.autodiff.differentiate { - val x = bindSymbolOrNull(x) ?: const(8.0) - x pow -2 - } - println(fixedExpression()) - // >>> 0.015625 - // It works! - - // The expression provides a bunch of operations: - // 1. Constant bindings (via `const` and `number`). - // 2. Variable bindings (via `bindVariable`, `bindVariableOrNull`). - // 3. Arithmetic operations (via `+`, `-`, `*`, and `-`). - // 4. Exponentiation (via `pow` or `power`). - // 5. `exp` and `ln`. - // 6. Trigonometrical functions (`sin`, `cos`, `tan`, `cot`). - // 7. Inverse trigonometrical functions (`asin`, `acos`, `atan`, `acot`). - // 8. Hyperbolic functions and inverse hyperbolic functions. -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt deleted file mode 100644 index fe7f48b72..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.fit - -import kotlinx.html.br -import kotlinx.html.h3 -import space.kscience.kmath.data.XYErrorColumnarData -import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.autodiff -import space.kscience.kmath.expressions.binding -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.operations.asIterable -import space.kscience.kmath.operations.toList -import space.kscience.kmath.optimization.* -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.real.map -import space.kscience.kmath.real.step -import space.kscience.plotly.* -import space.kscience.plotly.models.ScatterMode -import kotlin.math.abs -import kotlin.math.pow -import kotlin.math.sqrt - -// Forward declaration of symbols that will be used in expressions. -private val a by symbol -private val b by symbol -private val c by symbol -private val d by symbol -private val e by symbol - - -/** - * Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules. - */ -suspend fun main() { - //A generator for a normally distributed values - val generator = NormalDistribution(0.0, 1.0) - - //A chain/flow of random values with the given seed - val chain = generator.sample(RandomGenerator.default(112667)) - - - //Create a uniformly distributed x values like numpy.arrange - val x = 1.0..100.0 step 1.0 - - - //Perform an operation on each x value (much more effective, than numpy) - val y = x.map { it -> - val value = it.pow(2) + it + 1 - value + chain.next() * sqrt(value) - } - // this will also work, but less effective: - // val y = x.pow(2)+ x + 1 + chain.nextDouble() - - // create same errors for all xs - val yErr = y.map { sqrt(abs(it)) } - require(yErr.asIterable().all { it > 0 }) { "All errors must be strictly positive" } - - val result = XYErrorColumnarData.of(x, y, yErr).fitWith( - QowOptimizer, - Double.autodiff, - mapOf(a to 0.9, b to 1.2, c to 2.0, e to 1.0, d to 1.0, e to 0.0), - OptimizationParameters(a, b, c, d) - ) { arg -> - //bind variables to autodiff context - val a by binding - val b by binding - //Include default value for c if it is not provided as a parameter - val c = bindSymbolOrNull(c) ?: one - val d by binding - val e by binding - - a * arg.pow(2) + b * arg + c + d * arg.pow(3) + e / arg - } - - println("Resulting chi2/dof: ${result.chiSquaredOrNull}/${result.dof}") - - //display a page with plot and numerical results - val page = Plotly.page { - plot { - scatter { - mode = ScatterMode.markers - x(x) - y(y) - error_y { - array = yErr.toList() - } - name = "data" - } - scatter { - mode = ScatterMode.lines - x(x) - y(x.map { result.model(result.startPoint + result.resultPoint + (Symbol.x to it)) }) - name = "fit" - } - } - br() - h3 { - +"Fit result: ${result.resultPoint}" - } - h3 { - +"Chi2/dof = ${result.chiSquaredOrNull!! / result.dof}" - } - } - - page.makeFile() -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt index e8534d002..90542adf4 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt @@ -1,16 +1,5 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - package space.kscience.kmath.functions -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.ComplexField -import space.kscience.kmath.complex.ComplexField.div -import space.kscience.kmath.complex.ComplexField.minus -import space.kscience.kmath.complex.algebra -import space.kscience.kmath.integration.gaussIntegrator import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value import space.kscience.kmath.operations.DoubleField @@ -18,19 +7,11 @@ import kotlin.math.pow fun main() { //Define a function - val function: Function1D = { x -> 3 * x.pow(2) + 2 * x + 1 } + val function: UnivariateFunction = { x -> 3 * x.pow(2) + 2 * x + 1 } //get the result of the integration - val result = DoubleField.gaussIntegrator.integrate(0.0..10.0, function = function) + val result = DoubleField.integrate(0.0..10.0, function = function) //the value is nullable because in some cases the integration could not succeed println(result.value) - - - repeat(100000) { - Complex.algebra.gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double -> -// sin(1 / x) + i * cos(1 / x) - 1 / x - ComplexField.i / x - }.value - } } \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt deleted file mode 100644 index b4ce6ad2d..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.interpolation.SplineInterpolator -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.plotly.Plotly -import space.kscience.plotly.UnstablePlotlyAPI -import space.kscience.plotly.makeFile -import space.kscience.plotly.models.functionXY -import space.kscience.plotly.scatter -import kotlin.math.PI -import kotlin.math.sin - -@OptIn(UnstablePlotlyAPI::class) -fun main() { - val data = (0..10).map { - val x = it.toDouble() / 5 * PI - x to sin(x) - } - - val polynomial: PiecewisePolynomial = SplineInterpolator( - DoubleField, ::DoubleBuffer - ).interpolatePolynomials(data) - - val function = polynomial.asFunction(DoubleField, 0.0) - - val cmInterpolate = org.apache.commons.math3.analysis.interpolation.SplineInterpolator().interpolate( - data.map { it.first }.toDoubleArray(), - data.map { it.second }.toDoubleArray() - ) - - Plotly.plot { - scatter { - name = "interpolated" - x.numbers = data.map { it.first } - y.numbers = x.doubles.map { function(it) } - } - scatter { - name = "original" - functionXY(0.0..(2 * PI), 0.1) { sin(it) } - } - scatter { - name = "cm" - x.numbers = data.map { it.first } - y.numbers = x.doubles.map { cmInterpolate.value(it) } - } - }.makeFile() -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt deleted file mode 100644 index 7bcd96990..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.interpolation.splineInterpolator -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.real.map -import space.kscience.kmath.real.step -import space.kscience.plotly.Plotly -import space.kscience.plotly.UnstablePlotlyAPI -import space.kscience.plotly.makeFile -import space.kscience.plotly.models.functionXY -import space.kscience.plotly.scatter - -@OptIn(UnstablePlotlyAPI::class) -fun main() { - val function: Function1D = { x -> - if (x in 30.0..50.0) { - 1.0 - } else { - 0.0 - } - } - val xs = 0.0..100.0 step 0.5 - val ys = xs.map(function) - - val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(xs, ys) - - val polyFunction = polynomial.asFunction(DoubleField, 0.0) - - Plotly.plot { - scatter { - name = "interpolated" - functionXY(25.0..55.0, 0.1) { polyFunction(it) } - } - scatter { - name = "original" - functionXY(25.0..55.0, 0.1) { function(it) } - } - }.makeFile() -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt index baba2eb28..bd431c22c 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -1,32 +1,27 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - package space.kscience.kmath.functions -import space.kscience.kmath.integration.gaussIntegrator import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.nd.withNdAlgebra -import space.kscience.kmath.operations.algebra -import kotlin.math.pow +import space.kscience.kmath.nd.nd +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke -fun main(): Unit = Double.algebra.withNdAlgebra(2, 2) { +fun main(): Unit = DoubleField { + nd(2, 2) { - //Produce a diagonal StructureND - fun diagonal(v: Double) = structureND { (i, j) -> - if (i == j) v else 0.0 + //Produce a diagonal StructureND + fun diagonal(v: Double) = produce { (i, j) -> + if (i == j) v else 0.0 + } + + //Define a function in a nd space + val function: (Double) -> StructureND = { x: Double -> 3 * number(x).pow(2) + 2 * diagonal(x) + 1 } + + //get the result of the integration + val result = integrate(0.0..10.0, function = function) + + //the value is nullable because in some cases the integration could not succeed + println(result.value) } - - //Define a function in a nd space - val function: (Double) -> StructureND = { x: Double -> 3 * x.pow(2) + 2 * diagonal(x) + 1 } - - //get the result of the integration - val result = gaussIntegrator.integrate(0.0..10.0, function = function) - - //the value is nullable because in some cases the integration could not succeed - println(result.value) -} +} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt deleted file mode 100644 index 52451e9f3..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.jafama - -import space.kscience.kmath.operations.invoke - -fun main() { - val a = 2.0 - val b = StrictJafamaDoubleField { exp(a) } - println(JafamaDoubleField { b + a }) - println(StrictJafamaDoubleField { ln(b) }) -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt deleted file mode 100644 index 79eddc6c3..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.operations.algebra -import kotlin.random.Random -import kotlin.time.ExperimentalTime -import kotlin.time.measureTime - -@OptIn(ExperimentalTime::class) -fun main() { - val random = Random(12224) - val dim = 1000 - - //creating invertible matrix - val matrix1 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> - if (i <= j) random.nextDouble() else 0.0 - } - val matrix2 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> - if (i <= j) random.nextDouble() else 0.0 - } - - val time = measureTime { - with(Double.algebra.linearSpace) { - repeat(10) { - matrix1 dot matrix2 - } - } - } - - println(time) - -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt index 52ed8f05f..f7b284e89 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -22,8 +22,8 @@ fun main() { return DoubleBuffer(x.size) { i -> val h = sigma[i] / 5 val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 } - val f1 = this(x + dVector / 2) - val f0 = this(x - dVector / 2) + val f1 = invoke(x + dVector / 2) + val f0 = invoke(x - dVector / 2) (f1 - f0) / h } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt index 2447d06ed..51f439612 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt new file mode 100644 index 000000000..f99dd8c0e --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.operations + +import space.kscience.kmath.complex.Complex +import space.kscience.kmath.complex.complex +import space.kscience.kmath.nd.AlgebraND + +fun main() { + // 2d element + val element = AlgebraND.complex(2, 2).produce { (i, j) -> + Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble()) + } + println(element) + + // 1d element operation + val result = with(AlgebraND.complex(8)) { + val a = produce { (it) -> i * it - it.toDouble() } + val b = 3 + val c = Complex(1.0, 1.0) + + (a pow b) + c + } + + println(result) +} diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt deleted file mode 100644 index 77cfca4ae..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.algebra -import space.kscience.kmath.complex.ndAlgebra -import space.kscience.kmath.nd.BufferND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.structureND - -fun main() = Complex.algebra { - val complex = 2 + 2 * i - println(complex * 8 - 5 * i) - - //flat buffer - val buffer = with(bufferAlgebra) { - buffer(8) { Complex(it, -it) }.map { Complex(it.im, it.re) } - } - println(buffer) - - // 2d element - val element: BufferND = ndAlgebra.structureND(2, 2) { (i, j) -> - Complex(i - j, i + j) - } - println(element) - - // 1d element operation - val result: StructureND = ndAlgebra { - val a = structureND(8) { (it) -> i * it - it.toDouble() } - val b = 3 - val c = Complex(1.0, 1.0) - - (a pow b) + c - } - println(result) -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt deleted file mode 100644 index 4a5d783e1..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.commons.linear.CMLinearSpace -import space.kscience.kmath.linear.matrix -import space.kscience.kmath.nd.DoubleBufferND -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.viktor.ViktorStructureND -import space.kscience.kmath.viktor.viktorAlgebra - -fun main() { - val viktorStructure: ViktorStructureND = DoubleField.viktorAlgebra.structureND(ShapeND(2, 2)) { (i, j) -> - if (i == j) 2.0 else 0.0 - } - - val cmMatrix: Structure2D = CMLinearSpace.matrix(2, 2)(0.0, 1.0, 0.0, 3.0) - - val res: DoubleBufferND = DoubleField.ndAlgebra { - exp(viktorStructure) + 2.0 * cmMatrix - } - - println(res) -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt b/examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt deleted file mode 100644 index ca10fc290..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.series - -import kotlinx.datetime.Instant -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.bufferAlgebra -import kotlin.time.Duration - -fun SeriesAlgebra.Companion.time(zero: Instant, step: Duration) = MonotonicSeriesAlgebra( - bufferAlgebra = Double.algebra.bufferAlgebra, - offsetToLabel = { zero + step * it }, - labelToOffset = { (it - zero) / step } -) \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt b/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt deleted file mode 100644 index 0e10f1a9a..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt +++ /dev/null @@ -1,56 +0,0 @@ -package space.kscience.kmath.series - - -import kotlinx.html.h1 -import kotlinx.html.p -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.bufferAlgebra -import space.kscience.kmath.operations.toList -import space.kscience.kmath.stat.KMComparisonResult -import space.kscience.kmath.stat.ksComparisonStatistic -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.slice -import space.kscience.plotly.* -import kotlin.math.PI - -fun main() = with(Double.algebra.bufferAlgebra.seriesAlgebra()) { - - - fun Plot.plotSeries(name: String, buffer: Buffer) { - scatter { - this.name = name - x.numbers = buffer.labels - y.numbers = buffer.toList() - } - } - - - val s1 = series(100) { sin(2 * PI * it / 100) + 1.0 } - - val s2 = s1.slice(20..50).moveTo(40) - - val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 - val s4 = s3.map { ln(it) } - - val kmTest: KMComparisonResult = ksComparisonStatistic(s1, s2) - - Plotly.page { - h1 { +"This is my plot" } - p{ - +"Kolmogorov-smirnov test for s1 and s2: ${kmTest.value}" - } - plot{ - plotSeries("s1", s1) - plotSeries("s2", s2) - plotSeries("s3", s3) - plotSeries("s4", s4) - layout { - xaxis { - range(0.0..100.0) - } - } - } - - }.makeFile() - -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt index 031955e15..8e3cdf86f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,7 +10,6 @@ import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking import org.apache.commons.rng.sampling.distribution.BoxMullerNormalizedGaussianSampler import org.apache.commons.rng.simple.RandomSource -import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.samplers.GaussianSampler import java.time.Duration import java.time.Instant @@ -36,7 +35,7 @@ private suspend fun runKMathChained(): Duration { return Duration.between(startTime, Instant.now()) } -private fun runCMDirect(): Duration { +private fun runApacheDirect(): Duration { val rng = RandomSource.create(RandomSource.MT, 123L) val sampler = CMGaussianSampler.of( @@ -65,7 +64,7 @@ private fun runCMDirect(): Duration { * Comparing chain sampling performance with direct sampling performance */ fun main(): Unit = runBlocking(Dispatchers.Default) { - val directJob = async { runCMDirect() } + val directJob = async { runApacheDirect() } val chainJob = async { runKMathChained() } println("KMath Chained: ${chainJob.await()}") println("Apache Direct: ${directJob.await()}") diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt index 8e6d096ed..b319766e3 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,20 +7,22 @@ package space.kscience.kmath.stat import kotlinx.coroutines.runBlocking import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.combineWithState +import space.kscience.kmath.chains.collectWithState import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.random.RandomGenerator +/** + * The state of distribution averager. + */ private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0) /** * Averaging. */ -private fun Chain.mean(): Chain = combineWithState(AveragingChainState(), { it.copy() }) { chain -> +private fun Chain.mean(): Chain = collectWithState(AveragingChainState(), { it.copy() }) { chain -> val next = chain.next() num++ value += next - return@combineWithState value / num + return@collectWithState value / num } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt index 86d7c0d89..b30165f71 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -9,11 +9,10 @@ package space.kscience.kmath.structures import space.kscience.kmath.complex.* import space.kscience.kmath.linear.transpose +import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as2D -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.invoke import kotlin.system.measureTimeMillis @@ -21,8 +20,8 @@ fun main() { val dim = 1000 val n = 1000 - val realField = DoubleField.ndAlgebra(dim, dim) - val complexField: ComplexFieldND = ComplexField.ndAlgebra(dim, dim) + val realField = AlgebraND.real(dim, dim) + val complexField: ComplexFieldND = AlgebraND.complex(dim, dim) val realTime = measureTimeMillis { realField { @@ -50,12 +49,12 @@ fun main() { fun complexExample() { //Create a context for 2-d structure with complex values ComplexField { - withNdAlgebra(4, 8) { + nd(4, 8) { //a constant real-valued structure val x = one * 2.5 operator fun Number.plus(other: Complex) = Complex(this.toDouble() + other.re, other.im) //a structure generator specific to this context - val matrix = structureND { (k, l) -> k + l * i } + val matrix = produce { (k, l) -> k + l * i } //Perform sum val sum = matrix + x + 1.0 diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt index ba8f047a8..cc1f5f680 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -1,18 +1,17 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures -import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import org.nd4j.linalg.factory.Nd4j import space.kscience.kmath.nd.* -import space.kscience.kmath.nd4j.nd4j +import space.kscience.kmath.nd4j.Nd4jArrayField import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke -import space.kscience.kmath.viktor.ViktorFieldND +import space.kscience.kmath.viktor.ViktorNDField import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.system.measureTimeMillis @@ -23,43 +22,42 @@ internal inline fun measureAndPrint(title: String, block: () -> Unit) { println("$title completed in $time millis") } -@OptIn(DelicateCoroutinesApi::class) fun main() { // initializing Nd4j Nd4j.zeros(0) val dim = 1000 val n = 1000 - val shape = ShapeND(dim, dim) - - // specialized nd-field for Double. It works as generic Double field as well. - val doubleField = DoubleField.ndAlgebra - //A generic field. It should be used for objects, not primitives. - val genericField = BufferedFieldOpsND(DoubleField) + // automatically build context most suited for given type. + val autoField = AlgebraND.auto(DoubleField, dim, dim) + // specialized nd-field for Double. It works as generic Double field as well + val realField = AlgebraND.real(dim, dim) + //A generic boxing field. It should be used for objects, not primitives. + val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) // Nd4j specialized field. - val nd4jField = DoubleField.nd4j + val nd4jField = Nd4jArrayField.real(dim, dim) //viktor field - val viktorField = ViktorFieldND(dim, dim) + val viktorField = ViktorNDField(dim, dim) //parallel processing based on Java Streams - val parallelField = DoubleField.ndStreaming(dim, dim) + val parallelField = AlgebraND.realWithStream(dim, dim) measureAndPrint("Boxing addition") { - genericField { - var res: StructureND = one(shape) + boxingField { + var res: StructureND = one repeat(n) { res += 1.0 } } } measureAndPrint("Specialized addition") { - doubleField { - var res: StructureND = one(shape) + realField { + var res: StructureND = one repeat(n) { res += 1.0 } } } measureAndPrint("Nd4j specialized addition") { nd4jField { - var res: StructureND = one(shape) + var res: StructureND = one repeat(n) { res += 1.0 } } } @@ -78,8 +76,15 @@ fun main() { } } + measureAndPrint("Automatic field addition") { + autoField { + var res: StructureND = one + repeat(n) { res += 1.0 } + } + } + measureAndPrint("Lazy addition") { - val res = doubleField.one(shape).mapAsync(GlobalScope) { + val res = realField.one.mapAsync(GlobalScope) { var c = 0.0 repeat(n) { c += 1.0 diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt index 2ce2c21a6..d53cfa9b9 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -1,15 +1,14 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures -import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.operations.NumbersAddOperations import java.util.* import java.util.stream.IntStream @@ -17,33 +16,31 @@ import java.util.stream.IntStream * A demonstration implementation of NDField over Real using Java [java.util.stream.DoubleStream] for parallel * execution. */ -class StreamDoubleFieldND(override val shape: ShapeND) : FieldND, - NumbersAddOps>, +class StreamDoubleFieldND(override val shape: IntArray) : FieldND, + NumbersAddOperations>, ExtendedField> { - private val strides = ColumnStrides(shape) - override val elementAlgebra: DoubleField get() = DoubleField - override val zero: BufferND by lazy { structureND(shape) { zero } } - override val one: BufferND by lazy { structureND(shape) { one } } + private val strides = DefaultStrides(shape) + override val elementContext: DoubleField get() = DoubleField + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions - return structureND(shape) { d } + return produce { d } } - @OptIn(PerformancePitfall::class) private val StructureND.buffer: DoubleBuffer get() = when { !shape.contentEquals(this@StreamDoubleFieldND.shape) -> throw ShapeMismatchException( this@StreamDoubleFieldND.shape, shape ) - - this is BufferND && indices == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer + this is BufferND && this.strides == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } } - override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): BufferND { + override fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> val index = strides.index(offset) DoubleField.initializer(index) @@ -52,7 +49,6 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND.map( transform: DoubleField.(Double) -> Double, ): BufferND { @@ -60,7 +56,6 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND.mapIndexed( transform: DoubleField.(index: IntArray, Double) -> Double, ): BufferND { @@ -74,14 +69,13 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND, - right: StructureND, + override fun combine( + a: StructureND, + b: StructureND, transform: DoubleField.(Double, Double) -> Double, ): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> - DoubleField.transform(left.buffer.array[offset], right.buffer.array[offset]) + DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset]) }.toArray() return BufferND(strides, array.asBuffer()) } @@ -111,4 +105,4 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND): BufferND = arg.map { atanh(it) } } -fun DoubleField.ndStreaming(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(ShapeND(shape)) +fun AlgebraND.Companion.realWithStream(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(shape) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt index e6ff0ee28..0d5358354 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt @@ -1,45 +1,42 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures -import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.BufferND -import space.kscience.kmath.nd.ColumnStrides -import space.kscience.kmath.nd.ShapeND +import space.kscience.kmath.nd.DefaultStrides import kotlin.system.measureTimeMillis @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") -@OptIn(PerformancePitfall::class) fun main() { val n = 6000 val array = DoubleArray(n * n) { 1.0 } val buffer = DoubleBuffer(array) - val strides = ColumnStrides(ShapeND(n, n)) + val strides = DefaultStrides(intArrayOf(n, n)) val structure = BufferND(strides, buffer) measureTimeMillis { var res = 0.0 - strides.asSequence().forEach { res = structure[it] } + strides.indices().forEach { res = structure[it] } } // warmup val time1 = measureTimeMillis { var res = 0.0 - strides.asSequence().forEach { res = structure[it] } + strides.indices().forEach { res = structure[it] } } println("Structure reading finished in $time1 millis") val time2 = measureTimeMillis { var res = 0.0 - strides.asSequence().forEach { res = buffer[strides.offset(it)] } + strides.indices().forEach { res = buffer[strides.offset(it)] } } println("Buffer reading finished in $time2 millis") val time3 = measureTimeMillis { var res = 0.0 - strides.asSequence().forEach { res = array[strides.offset(it)] } + strides.indices().forEach { res = array[strides.offset(it)] } } println("Array reading finished in $time3 millis") } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt index 14c058417..dea7095a8 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt @@ -1,27 +1,20 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures -import space.kscience.kmath.nd.BufferND -import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.mapToBuffer +import space.kscience.kmath.nd.mapToBuffer import kotlin.system.measureTimeMillis -private inline fun BufferND.mapToBufferND( - bufferFactory: BufferFactory = BufferFactory.auto(), - crossinline block: (T) -> R, -): BufferND = BufferND(indices, buffer.mapToBuffer(bufferFactory, block)) - @Suppress("UNUSED_VARIABLE") fun main() { val n = 6000 - val structure = StructureND.buffered(ShapeND(n, n), Buffer.Companion::auto) { 1.0 } - structure.mapToBufferND { it + 1 } // warm-up - val time1 = measureTimeMillis { val res = structure.mapToBufferND { it + 1 } } + val structure = StructureND.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 } + structure.mapToBuffer { it + 1 } // warm-up + val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } } println("Structure mapping finished in $time1 millis") val array = DoubleArray(n * n) { 1.0 } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt deleted file mode 100644 index 2ac0dc6a4..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.structures - -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.buffer -import space.kscience.kmath.operations.bufferAlgebra -import space.kscience.kmath.operations.withSize - -inline fun MutableBuffer.Companion.same( - n: Int, - value: R -): MutableBuffer = auto(n) { value } - - -fun main() { - with(DoubleField.bufferAlgebra.withSize(5)) { - println(number(2.0) + buffer(1, 2, 3, 4, 5)) - } -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt index 1ba0e3503..955f86fa9 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -19,7 +19,7 @@ private fun DMatrixContext.simple() { } private object D5 : Dimension { - override val dim: Int = 5 + override val dim: UInt = 5u } private fun DMatrixContext.custom() { diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt deleted file mode 100644 index 2c570ea34..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.contentEquals -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.randomNormal -import space.kscience.kmath.tensors.core.randomNormalLike -import kotlin.math.abs - -// OLS estimator using SVD - -fun main() { - //seed for random - val randSeed = 100500L - - // work in context with linear operations - DoubleTensorAlgebra { - // take coefficient vector from normal distribution - val alpha = randomNormal( - ShapeND(5), - randSeed - ) + fromArray( - ShapeND(5), - doubleArrayOf(1.0, 2.5, 3.4, 5.0, 10.1) - ) - - println("Real alpha:\n$alpha") - - // also take sample of size 20 from normal distribution for x - val x = randomNormal( - ShapeND(20, 5), - randSeed - ) - - // calculate y and add gaussian noise (N(0, 0.05)) - val y = x dot alpha - y += randomNormalLike(y, randSeed) * 0.05 - - // now restore the coefficient vector with OSL estimator with SVD - val (u, singValues, v) = svd(x) - - // we have to make sure the singular values of the matrix are not close to zero - println("Singular values:\n$singValues") - - - // inverse Sigma matrix can be restored from singular values with diagonalEmbedding function - val sigma = diagonalEmbedding(singValues.map { if (abs(it) < 1e-3) 0.0 else 1.0 / it }) - - val alphaOLS = v dot sigma dot u.transposed() dot y - println( - "Estimated alpha:\n" + - "$alphaOLS" - ) - - // figure out MSE of approximation - fun mse(yTrue: DoubleTensor, yPred: DoubleTensor): Double { - require(yTrue.shape.size == 1) - require(yTrue.shape contentEquals yPred.shape) - - val diff = yTrue - yPred - return sqrt(diff.dot(diff)).value() - } - - println("MSE: ${mse(alpha, alphaOLS)}") - } -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt deleted file mode 100644 index fb774a39d..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.tensors.core.* - - -// simple PCA - -fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with broadcast methods - val seed = 100500L - - // assume x is range from 0 until 10 - val x = fromArray( - ShapeND(10), - DoubleArray(10) { it.toDouble() } - ) - - // take y dependent on x with noise - val y = 2.0 * x + (3.0 + randomNormalLike(x, seed) * 1.5) - - println("x:\n$x") - println("y:\n$y") - - // stack them into single dataset - val dataset = stack(listOf(x, y)).transposed() - - // normalize both x and y - val xMean = mean(x) - val yMean = mean(y) - - val xStd = std(x) - val yStd = std(y) - - val xScaled: DoubleTensor = (x - xMean) / xStd - val yScaled: DoubleTensor = (y - yMean) / yStd - - // save means ans standard deviations for further recovery - val mean = fromArray( - ShapeND(2), - doubleArrayOf(xMean, yMean) - ) - println("Means:\n$mean") - - val std = fromArray( - ShapeND(2), - doubleArrayOf(xStd, yStd) - ) - println("Standard deviations:\n$std") - - // calculate the covariance matrix of scaled x and y - val covMatrix = covariance(listOf(xScaled.asDoubleTensor1D(), yScaled.asDoubleTensor1D())) - println("Covariance matrix:\n$covMatrix") - - // and find out eigenvector of it - val (_, evecs) = symEig(covMatrix) - val v = evecs.getTensor(0) - println("Eigenvector:\n$v") - - // reduce dimension of dataset - val datasetReduced = v dot stack(listOf(xScaled, yScaled)) - println("Reduced data:\n$datasetReduced") - - // we can restore original data from reduced data; - // for example, find 7th element of dataset. - val n = 7 - val restored = (datasetReduced.getTensor(n) dot v.view(ShapeND(1, 2))) * std + mean - println("Original value:\n${dataset.getTensor(n)}") - println("Restored value:\n$restored") -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt deleted file mode 100644 index 45c2ff120..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.tensors.core.randomNormal -import space.kscience.kmath.tensors.core.tensorAlgebra -import space.kscience.kmath.tensors.core.withBroadcast - - -// Dataset normalization - -fun main() = Double.tensorAlgebra.withBroadcast { // work in context with broadcast methods - // take dataset of 5-element vectors from normal distribution - val dataset = randomNormal(ShapeND(100, 5)) * 1.5 // all elements from N(0, 1.5) - - dataset += fromArray( - ShapeND(5), - doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // row means - ) - - - // find out mean and standard deviation of each column - val mean = mean(dataset, 0, false) - val std = std(dataset, 0, false) - - println("Mean:\n$mean") - println("Standard deviation:\n$std") - - // also, we can calculate other statistic as minimum and maximum of rows - println("Minimum:\n${dataset.min(0, false)}") - println("Maximum:\n${dataset.max(0, false)}") - - // now we can scale dataset with mean normalization - val datasetScaled = (dataset - mean) / std - - // find out mean and standardDiviation of scaled dataset - - println("Mean of scaled:\n${mean(datasetScaled, 0, false)}") - println("Mean of scaled:\n${std(datasetScaled, 0, false)}") -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt deleted file mode 100644 index 238696cf9..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.tensorAlgebra -import space.kscience.kmath.tensors.core.withBroadcast - -// solving linear system with LUP decomposition - -fun main() = Double.tensorAlgebra.withBroadcast {// work in context with linear operations - - // set true value of x - val trueX = fromArray( - ShapeND(4), - doubleArrayOf(-2.0, 1.5, 6.8, -2.4) - ) - - // and A matrix - val a = fromArray( - ShapeND(4, 4), - doubleArrayOf( - 0.5, 10.5, 4.5, 1.0, - 8.5, 0.9, 12.8, 0.1, - 5.56, 9.19, 7.62, 5.45, - 1.0, 2.0, -3.0, -2.5 - ) - ) - - // calculate y value - val b = a dot trueX - - // check out A and b - println("A:\n$a") - println("b:\n$b") - - // solve `Ax = b` system using LUP decomposition - - // get P, L, U such that PA = LU - val (p, l, u) = lu(a) - - // check P is permutation matrix - println("P:\n$p") - // L is lower triangular matrix and U is upper triangular matrix - println("L:\n$l") - println("U:\n$u") - // and PA = LU - println("PA:\n${p dot a}") - println("LU:\n${l dot u}") - - /* Ax = b; - PAx = Pb; - LUx = Pb; - let y = Ux, then - Ly = Pb -- this system can be easily solved, since the matrix L is lower triangular; - Ux = y can be solved the same way, since the matrix L is upper triangular - */ - - - - // this function returns solution x of a system lx = b, l should be lower triangular - fun solveLT(l: DoubleTensor, b: DoubleTensor): DoubleTensor { - val n = l.shape[0] - val x = zeros(ShapeND(n)) - for (i in 0 until n) { - x[intArrayOf(i)] = (b[intArrayOf(i)] - l.getTensor(i).dot(x).value()) / l[intArrayOf(i, i)] - } - return x - } - - val y = solveLT(l, p dot b) - - // solveLT(l, b) function can be easily adapted for upper triangular matrix by the permutation matrix revMat - // create it by placing ones on side diagonal - val revMat = zeroesLike(u) - val n = revMat.shape[0] - for (i in 0 until n) { - revMat[intArrayOf(i, n - 1 - i)] = 1.0 - } - - // solution of system ux = b, u should be upper triangular - fun solveUT(u: DoubleTensor, b: DoubleTensor): DoubleTensor = revMat dot solveLT( - revMat dot u dot revMat, revMat dot b - ) - - val x = solveUT(u, y) - - println("True x:\n$trueX") - println("x founded with LU method:\n$x") -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt deleted file mode 100644 index 67e0631e7..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors - -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.ndarray -import org.jetbrains.kotlinx.multik.default.DefaultEngine -import space.kscience.kmath.multik.MultikDoubleAlgebra -import space.kscience.kmath.nd.one - - -val multikAlgebra = MultikDoubleAlgebra(DefaultEngine()) - -fun main(): Unit = with(multikAlgebra) { - val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType().wrap() - val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)).wrap() - one(a.shape) - a + b * 3.0 -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt deleted file mode 100644 index 8fd5ae5ad..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.contentEquals -import space.kscience.kmath.operations.asIterable -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.* -import kotlin.math.sqrt - -const val seed = 100500L - -// Simple feedforward neural network with backpropagation training - -// interface of network layer -interface Layer { - fun forward(input: DoubleTensor): DoubleTensor - fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor -} - -// activation layer -open class Activation( - val activation: (DoubleTensor) -> DoubleTensor, - val activationDer: (DoubleTensor) -> DoubleTensor, -) : Layer { - override fun forward(input: DoubleTensor): DoubleTensor { - return activation(input) - } - - override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor { - return DoubleTensorAlgebra { outputError * activationDer(input) } - } -} - -fun relu(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - x.map { if (it > 0) it else 0.0 } -} - -fun reluDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - x.map { if (it > 0) 1.0 else 0.0 } -} - -// activation layer with relu activator -class ReLU : Activation(::relu, ::reluDer) - -fun sigmoid(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - 1.0 / (1.0 + exp((-x))) -} - -fun sigmoidDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - sigmoid(x) * (1.0 - sigmoid(x)) -} - -// activation layer with sigmoid activator -class Sigmoid : Activation(::sigmoid, ::sigmoidDer) - -// dense layer -class Dense( - private val inputUnits: Int, - private val outputUnits: Int, - private val learningRate: Double = 0.1, -) : Layer { - - private val weights: DoubleTensor = DoubleTensorAlgebra { - randomNormal( - ShapeND(inputUnits, outputUnits), - seed - ) * sqrt(2.0 / (inputUnits + outputUnits)) - } - - private val bias: DoubleTensor = DoubleTensorAlgebra { zeros(ShapeND(outputUnits)) } - - override fun forward(input: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra { - (input dot weights) + bias - } - - override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - val gradInput = outputError dot weights.transposed() - - val gradW = input.transposed() dot outputError - val gradBias = mean(structureND = outputError, dim = 0, keepDim = false) * input.shape[0].toDouble() - - weights -= learningRate * gradW - bias -= learningRate * gradBias - - gradInput - } - -} - -// simple accuracy equal to the proportion of correct answers -fun accuracy(yPred: DoubleTensor, yTrue: DoubleTensor): Double { - check(yPred.shape contentEquals yTrue.shape) - val n = yPred.shape[0] - var correctCnt = 0 - for (i in 0 until n) { - if (yPred[intArrayOf(i, 0)] == yTrue[intArrayOf(i, 0)]) { - correctCnt += 1 - } - } - return correctCnt.toDouble() / n.toDouble() -} - -// neural network class -class NeuralNetwork(private val layers: List) { - private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra { - - val onesForAnswers = zeroesLike(yPred) - yTrue.source.asIterable().forEachIndexed { index, labelDouble -> - val label = labelDouble.toInt() - onesForAnswers[intArrayOf(index, label)] = 1.0 - } - - val softmaxValue = exp(yPred) / exp(yPred).sum(dim = 1, keepDim = true) - - (-onesForAnswers + softmaxValue) / (yPred.shape[0].toDouble()) - } - - - private fun forward(x: DoubleTensor): List { - var input = x - - return buildList { - layers.forEach { layer -> - val output = layer.forward(input) - add(output) - input = output - } - } - } - - private fun train(xTrain: DoubleTensor, yTrain: DoubleTensor) { - val layerInputs = buildList { - add(xTrain) - addAll(forward(xTrain)) - } - - var lossGrad = softMaxLoss(layerInputs.last(), yTrain) - - layers.zip(layerInputs).reversed().forEach { (layer, input) -> - lossGrad = layer.backward(input, lossGrad) - } - } - - fun fit(xTrain: DoubleTensor, yTrain: DoubleTensor, batchSize: Int, epochs: Int) = DoubleTensorAlgebra { - fun iterBatch(x: DoubleTensor, y: DoubleTensor): Sequence> = sequence { - val n = x.shape[0] - val shuffledIndices = (0 until n).shuffled() - for (i in 0 until n step batchSize) { - val excerptIndices = shuffledIndices.drop(i).take(batchSize).toIntArray() - val batch = x.rowsByIndices(excerptIndices) to y.rowsByIndices(excerptIndices) - yield(batch) - } - } - - for (epoch in 0 until epochs) { - println("Epoch ${epoch + 1}/$epochs") - for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) { - train(xBatch, yBatch) - } - println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true).toDoubleTensor())}") - } - } - - fun predict(x: DoubleTensor): DoubleTensor { - return forward(x).last() - } - -} - - -fun main() = BroadcastDoubleTensorAlgebra { - val features = 5 - val sampleSize = 250 - val trainSize = 180 - //val testSize = sampleSize - trainSize - - // take sample of features from normal distribution - val x = randomNormal(ShapeND(sampleSize, features), seed) * 2.5 - - x += fromArray( - ShapeND(5), - doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // row means - ) - - - // define class like '1' if the sum of features > 0 and '0' otherwise - val y = fromArray( - ShapeND(sampleSize, 1), - DoubleArray(sampleSize) { i -> - if (x.getTensor(i).sum() > 0.0) { - 1.0 - } else { - 0.0 - } - } - ) - - // split train ans test - val trainIndices = (0 until trainSize).toList().toIntArray() - val testIndices = (trainSize until sampleSize).toList().toIntArray() - - val xTrain = x.rowsByIndices(trainIndices) - val yTrain = y.rowsByIndices(trainIndices) - - val xTest = x.rowsByIndices(testIndices) - val yTest = y.rowsByIndices(testIndices) - - // build model - val layers = buildList { - add(Dense(features, 64)) - add(ReLU()) - add(Dense(64, 16)) - add(ReLU()) - add(Dense(16, 2)) - add(Sigmoid()) - } - val model = NeuralNetwork(layers) - - // fit it with train data - model.fit(xTrain, yTrain, batchSize = 20, epochs = 10) - - // make prediction - val prediction = model.predict(xTest) - - // process raw prediction via argMax - val predictionLabels = prediction.argMax(1, true).toDoubleTensor() - - // find out accuracy - val acc = accuracy(yTest, predictionLabels) - println("Test accuracy:$acc") - -} diff --git a/gradle.properties b/gradle.properties index e33106c0c..7e9516660 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,15 +2,12 @@ # Copyright 2018-2021 KMath contributors. # Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. # + kotlin.code.style=official +kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.mpp.stability.nowarn=true -kotlin.native.ignoreDisabledTargets=true - +kotlin.native.enableDependencyPropagation=false +kotlin.parallel.tasks.in.project=true org.gradle.configureondemand=true -org.gradle.jvmargs=-Xmx4096m - -toolsVersion=0.14.6-kotlin-1.8.20 - - +org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G org.gradle.parallel=true -org.gradle.workers.max=4 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4..e708b1c02 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fae08049a..442d9132e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c78733..6ad9eb930 100755 --- a/gradlew +++ b/gradlew @@ -1,117 +1,72 @@ -#!/bin/sh +#!/usr/bin/env sh # -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Copyright 2018-2021 KMath contributors. +# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. # ############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# +## +## Gradle start up script for UN*X +## ############################################################################## # Attempt to set APP_HOME - # Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} +APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum +MAX_FD="maximum" warn () { echo "$*" -} >&2 +} die () { echo echo "$*" echo exit 1 -} >&2 +} # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -121,9 +76,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java + JAVACMD="$JAVA_HOME/jre/sh/java" else - JAVACMD=$JAVA_HOME/bin/java + JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -132,7 +87,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD=java + JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -140,95 +95,80 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi fi -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi # For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=$( cygpath --unix "$JAVACMD" ) + JAVACMD=`cygpath --unix "$JAVACMD"` - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" exec "$JAVACMD" "$@" diff --git a/kmath-ast/README.md b/kmath-ast/README.md index d85a18e1c..b1ef9c7d3 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -1,191 +1,129 @@ # Module kmath-ast -Extensions to MST API: transformations, dynamic compilation and visualization. +Abstract syntax tree expression representation and related optimizations. - - [expression-language](src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser + - [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser + - [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation + - [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure + - [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter - [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler - [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler - - [rendering](src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.4.0-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-6`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } - mavenCentral() + maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap } dependencies { - implementation 'space.kscience:kmath-ast:0.4.0-dev-1' + implementation 'space.kscience:kmath-ast:0.3.0-dev-6' } ``` **Gradle Kotlin DSL:** ```kotlin repositories { maven("https://repo.kotlin.link") - mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap + maven("https://dl.bintray.com/hotkeytlt/maven") // required for a } dependencies { - implementation("space.kscience:kmath-ast:0.4.0-dev-1") + implementation("space.kscience:kmath-ast:0.3.0-dev-6") } ``` -## Parsing expressions - -In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances. - -Supported literals: -1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`. -2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`—all parsed either as `kotlin.Long` or `kotlin.Double`. - -Supported binary operators (from the highest precedence to the lowest one): -1. `^` -2. `*`, `/` -3. `+`, `-` - -Supported unary operator: -1. `-`, e. g. `-x` - -Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples: -1. `sin(x)` -2. `add(x, y)` - ## Dynamic expression code generation ### On JVM -`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a -special implementation of `Expression` with implemented `invoke` function. +`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds +a special implementation of `Expression` with implemented `invoke` function. -For example, the following code: +For example, the following builder: ```kotlin -import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.operations.DoubleField +DoubleField.mstInField { symbol("x") + 2 }.compile() +``` -"x^3-x+3".parseMath().compileToExpression(DoubleField) -``` - -… leads to generation of bytecode, which can be decompiled to the following Java class: +… leads to generation of bytecode, which can be decompiled to the following Java class: ```java -import java.util.*; -import kotlin.jvm.functions.*; -import space.kscience.kmath.asm.internal.*; -import space.kscience.kmath.complex.*; -import space.kscience.kmath.expressions.*; +package space.kscience.kmath.asm.generated; -public final class CompiledExpression_45045_0 implements Expression { +import java.util.Map; +import kotlin.jvm.functions.Function2; +import space.kscience.kmath.asm.internal.MapIntrinsics; +import space.kscience.kmath.expressions.Expression; +import space.kscience.kmath.expressions.Symbol; + +public final class AsmCompiledExpression_45045_0 implements Expression { private final Object[] constants; - public Complex invoke(Map arguments) { - Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x"); - return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]); - } -} -``` - -For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: - -```java -import java.util.*; -import space.kscience.kmath.asm.internal.*; -import space.kscience.kmath.expressions.*; - -public final class CompiledExpression_-386104628_0 implements DoubleExpression { - private final SymbolIndexer indexer; - - public SymbolIndexer getIndexer() { - return this.indexer; - } - - public double invoke(double[] arguments) { - double var2 = arguments[0]; - return Math.pow(var2, 3.0D) - var2 + 3.0D; - } - public final Double invoke(Map arguments) { - double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); - return Math.pow(var2, 3.0D) - var2 + 3.0D; + return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2); + } + + public AsmCompiledExpression_45045_0(Object[] constants) { + this.constants = constants; } } + ``` -Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. +### Example Usage -#### Limitations +This API extends MST and MstExpression, so you may optimize as both of them: -- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead. -- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders. +```kotlin +DoubleField.mstInField { symbol("x") + 2 }.compile() +DoubleField.expression("x+2".parseMath()) +``` + +#### Known issues + +- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid + class loading overhead. +- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. ### On JS A similar feature is also available on JS. ```kotlin -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.* -import space.kscience.kmath.estree.* - -MstField { x + 2 }.compileToExpression(DoubleField) +DoubleField.mstInField { symbol("x") + 2 }.compile() ``` The code above returns expression implemented with such a JS function: ```js var executable = function (constants, arguments) { - return constants[1](constants[0](arguments, "x"), 2); + return constants[1](constants[0](arguments, "x"), 2); }; ``` -JS also supports experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. -Currently, only expressions inside `DoubleField` and `IntRing` are supported. +#### Known issues -```kotlin -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.* -import space.kscience.kmath.wasm.* - -MstField { x + 2 }.compileToExpression(DoubleField) -``` - -An example of emitted Wasm IR in the form of WAT: - -```lisp -(func \$executable (param \$0 f64) (result f64) - (f64.add - (local.get \$0) - (f64.const 2) - ) -) -``` - -#### Limitations - -- ESTree expression compilation uses `eval` which can be unavailable in several environments. -- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/). +- This feature uses `eval` which can be unavailable in several environments. ## Rendering expressions -kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax. +kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax. Example usage: ```kotlin import space.kscience.kmath.ast.* import space.kscience.kmath.ast.rendering.* -import space.kscience.kmath.misc.* -@OptIn(UnstableKMathAPI::class) public fun main() { - val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(12)+x^(2/3)".parseMath() + val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath() val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst) val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax) println("LaTeX:") @@ -197,80 +135,15 @@ public fun main() { } ``` -Result LaTeX: +Result LaTeX: -$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\\,x\right)}{2\times10^{10}+x^{3}}}{12}+x^{2/3}$$ +![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D) -Result MathML (can be used with MathJax or other renderers): - -
+Result MathML (embedding MathML is not allowed by GitHub Markdown): ```html - - - exp - - - - x - - - - - - - - - arcsin - - - 2 - - x - - - - 2 - × - - - 10 - - - 10 - - - + - - - x - - - 3 - - - - - - - 12 - - - + - - - x - - - 2 - / - 3 - - - - +ex-sin-12x2×1010+x3-12 ``` -
- -It is also possible to create custom algorithms of render, and even add support of other markup languages +It is also possible to create custom algorithms of render, and even add support of other markup languages (see API reference). diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 7cdb745f0..3f309b67c 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -1,82 +1,99 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity + plugins { - id("space.kscience.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") } -kscience{ - jvm() - js() - native() - - dependencies { - api(projects.kmathCore) - api("com.github.h0tk3y.betterParse:better-parse:0.4.4") - } - - testDependencies { - implementation(projects.kmathComplex) - } - - dependencies(jsMain) { - implementation(npm("astring", "1.7.5")) - implementation(npm("binaryen", "101.0.0")) - implementation(npm("js-base64", "3.6.1")) - } - - dependencies(jvmMain){ - implementation("org.ow2.asm:asm-commons:9.2") - } - -} - -kotlin { - js { - nodejs { - testTask { - useMocha().timeout = "0" - } - } - - browser { - testTask { - useMocha().timeout = "0" - } +kotlin.js { + nodejs { + testTask { + useMocha().timeout = "0" } } - sourceSets { - filter { it.name.contains("test", true) } - .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) - .forEach { it.optIn("space.kscience.kmath.UnstableKMathAPI") } + browser { + testTask { + useMocha().timeout = "0" + } } } -if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") { - tasks.withType { - jvmArgs("-Dspace.kscience.kmath.ast.dump.generated.classes=1") +kotlin.sourceSets { + commonMain { + dependencies { + api(project(":kmath-core")) + } } + + commonTest { + dependencies { + implementation(project(":kmath-complex")) + } + } + + jsMain { + dependencies { + implementation(npm("astring", "1.7.0")) + } + } + + jvmMain { + dependencies { + api("com.github.h0tk3y.betterParse:better-parse:0.4.1") + implementation("org.ow2.asm:asm:9.1") + implementation("org.ow2.asm:asm-commons:9.1") + } + } +} + +//Workaround for https://github.com/Kotlin/dokka/issues/1455 +tasks.dokkaHtml { + dependsOn(tasks.build) } readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + maturity = Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( id = "expression-language", - ref = "src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt" - ) { "Expression language and its parser" } + description = "Expression language and its parser", + ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt" + ) + + feature( + id = "mst", + description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation", + ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt" + ) + + feature( + id = "mst-building", + description = "MST building algebraic structure", + ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt" + ) + + feature( + id = "mst-interpreter", + description = "MST interpreter", + ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt" + ) feature( id = "mst-jvm-codegen", + description = "Dynamic MST to JVM bytecode compiler", ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt" - ) { "Dynamic MST to JVM bytecode compiler" } + ) feature( id = "mst-js-codegen", + description = "Dynamic MST to JS compiler", ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt" - ) { "Dynamic MST to JS compiler" } - - feature( - id = "rendering", - ref = "src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt" - ) { "Extendable MST rendering" } + ) } diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md index 96bbfbf5a..9ed44d584 100644 --- a/kmath-ast/docs/README-TEMPLATE.md +++ b/kmath-ast/docs/README-TEMPLATE.md @@ -1,162 +1,96 @@ # Module kmath-ast -Extensions to MST API: transformations, dynamic compilation and visualization. +Abstract syntax tree expression representation and related optimizations. ${features} ${artifact} -## Parsing expressions - -In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances. - -Supported literals: -1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`. -2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`—all parsed either as `kotlin.Long` or `kotlin.Double`. - -Supported binary operators (from the highest precedence to the lowest one): -1. `^` -2. `*`, `/` -3. `+`, `-` - -Supported unary operator: -1. `-`, e. g. `-x` - -Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples: -1. `sin(x)` -2. `add(x, y)` - ## Dynamic expression code generation ### On JVM -`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a -special implementation of `Expression` with implemented `invoke` function. +`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds +a special implementation of `Expression` with implemented `invoke` function. -For example, the following code: +For example, the following builder: ```kotlin -import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.operations.DoubleField +DoubleField.mstInField { symbol("x") + 2 }.compile() +``` -"x^3-x+3".parseMath().compileToExpression(DoubleField) -``` - -… leads to generation of bytecode, which can be decompiled to the following Java class: +… leads to generation of bytecode, which can be decompiled to the following Java class: ```java -import java.util.*; -import kotlin.jvm.functions.*; -import space.kscience.kmath.asm.internal.*; -import space.kscience.kmath.complex.*; -import space.kscience.kmath.expressions.*; +package space.kscience.kmath.asm.generated; -public final class CompiledExpression_45045_0 implements Expression { +import java.util.Map; +import kotlin.jvm.functions.Function2; +import space.kscience.kmath.asm.internal.MapIntrinsics; +import space.kscience.kmath.expressions.Expression; +import space.kscience.kmath.expressions.Symbol; + +public final class AsmCompiledExpression_45045_0 implements Expression { private final Object[] constants; - public Complex invoke(Map arguments) { - Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x"); - return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]); - } -} -``` - -For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: - -```java -import java.util.*; -import space.kscience.kmath.asm.internal.*; -import space.kscience.kmath.expressions.*; - -public final class CompiledExpression_-386104628_0 implements DoubleExpression { - private final SymbolIndexer indexer; - - public SymbolIndexer getIndexer() { - return this.indexer; - } - - public double invoke(double[] arguments) { - double var2 = arguments[0]; - return Math.pow(var2, 3.0D) - var2 + 3.0D; - } - public final Double invoke(Map arguments) { - double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); - return Math.pow(var2, 3.0D) - var2 + 3.0D; + return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2); + } + + public AsmCompiledExpression_45045_0(Object[] constants) { + this.constants = constants; } } + ``` -Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. +### Example Usage -#### Limitations +This API extends MST and MstExpression, so you may optimize as both of them: -- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead. -- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders. +```kotlin +DoubleField.mstInField { symbol("x") + 2 }.compile() +DoubleField.expression("x+2".parseMath()) +``` + +#### Known issues + +- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid + class loading overhead. +- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. ### On JS A similar feature is also available on JS. ```kotlin -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.* -import space.kscience.kmath.estree.* - -MstField { x + 2 }.compileToExpression(DoubleField) +DoubleField.mstInField { symbol("x") + 2 }.compile() ``` The code above returns expression implemented with such a JS function: ```js var executable = function (constants, arguments) { - return constants[1](constants[0](arguments, "x"), 2); + return constants[1](constants[0](arguments, "x"), 2); }; ``` -JS also supports experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. -Currently, only expressions inside `DoubleField` and `IntRing` are supported. +#### Known issues -```kotlin -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.* -import space.kscience.kmath.wasm.* - -MstField { x + 2 }.compileToExpression(DoubleField) -``` - -An example of emitted Wasm IR in the form of WAT: - -```lisp -(func \$executable (param \$0 f64) (result f64) - (f64.add - (local.get \$0) - (f64.const 2) - ) -) -``` - -#### Limitations - -- ESTree expression compilation uses `eval` which can be unavailable in several environments. -- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/). +- This feature uses `eval` which can be unavailable in several environments. ## Rendering expressions -kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax. +kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax. Example usage: ```kotlin import space.kscience.kmath.ast.* import space.kscience.kmath.ast.rendering.* -import space.kscience.kmath.misc.* -@OptIn(UnstableKMathAPI::class) public fun main() { - val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(12)+x^(2/3)".parseMath() + val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath() val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst) val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax) println("LaTeX:") @@ -168,80 +102,15 @@ public fun main() { } ``` -Result LaTeX: +Result LaTeX: -$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\\,x\right)}{2\times10^{10}+x^{3}}}{12}+x^{2/3}$$ +![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D) -Result MathML (can be used with MathJax or other renderers): - -
+Result MathML (embedding MathML is not allowed by GitHub Markdown): ```html - - - exp - - - - x - - - - - - - - - arcsin - - - 2 - - x - - - - 2 - × - - - 10 - - - 10 - - - + - - - x - - - 3 - - - - - - - 12 - - - + - - - x - - - 2 - / - 3 - - - - +ex-sin-12x2×1010+x3-12 ``` -
- -It is also possible to create custom algorithms of render, and even add support of other markup languages +It is also possible to create custom algorithms of render, and even add support of other markup languages (see API reference). diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt deleted file mode 100644 index e82f7a3ab..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.NumericAlgebra - -/** - * MST form where all values belong to the type [T]. It is optimal for constant folding, dynamic compilation, etc. - * - * @param T the type. - */ -public sealed interface TypedMst { - /** - * A node containing a unary operation. - * - * @param T the type. - * @property operation The identifier of operation. - * @property function The function implementing this operation. - * @property value The argument of this operation. - */ - public class Unary(public val operation: String, public val function: (T) -> T, public val value: TypedMst) : - TypedMst { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - other as Unary<*> - if (operation != other.operation) return false - if (value != other.value) return false - return true - } - - override fun hashCode(): Int { - var result = operation.hashCode() - result = 31 * result + value.hashCode() - return result - } - - override fun toString(): String = "Unary(operation=$operation, value=$value)" - } - - /** - * A node containing binary operation. - * - * @param T the type. - * @property operation The identifier of operation. - * @property function The binary function implementing this operation. - * @property left The left operand. - * @property right The right operand. - */ - public class Binary( - public val operation: String, - public val function: Function, - public val left: TypedMst, - public val right: TypedMst, - ) : TypedMst { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as Binary<*> - - if (operation != other.operation) return false - if (left != other.left) return false - if (right != other.right) return false - - return true - } - - override fun hashCode(): Int { - var result = operation.hashCode() - result = 31 * result + left.hashCode() - result = 31 * result + right.hashCode() - return result - } - - override fun toString(): String = "Binary(operation=$operation, left=$left, right=$right)" - } - - /** - * The non-numeric constant value. - * - * @param T the type. - * @property value The held value. - * @property number The number this value corresponds. - */ - public class Constant(public val value: T, public val number: Number?) : TypedMst { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - other as Constant<*> - if (value != other.value) return false - if (number != other.number) return false - return true - } - - override fun hashCode(): Int { - var result = value?.hashCode() ?: 0 - result = 31 * result + (number?.hashCode() ?: 0) - return result - } - - override fun toString(): String = "Constant(value=$value, number=$number)" - } - - /** - * The node containing a variable - * - * @param T the type. - * @property symbol The symbol of the variable. - */ - public class Variable(public val symbol: Symbol) : TypedMst { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - other as Variable<*> - if (symbol != other.symbol) return false - return true - } - - override fun hashCode(): Int = symbol.hashCode() - override fun toString(): String = "Variable(symbol=$symbol)" - } -} - -/** - * Interprets the [TypedMst] node with this [Algebra] and [arguments]. - */ -public fun TypedMst.interpret(algebra: Algebra, arguments: Map): T = when (this) { - is TypedMst.Unary -> algebra.unaryOperation(operation, interpret(algebra, arguments)) - - is TypedMst.Binary -> when { - algebra is NumericAlgebra && left is TypedMst.Constant && left.number != null -> - algebra.leftSideNumberOperation(operation, left.number, right.interpret(algebra, arguments)) - - algebra is NumericAlgebra && right is TypedMst.Constant && right.number != null -> - algebra.rightSideNumberOperation(operation, left.interpret(algebra, arguments), right.number) - - else -> algebra.binaryOperation( - operation, - left.interpret(algebra, arguments), - right.interpret(algebra, arguments), - ) - } - - is TypedMst.Constant -> value - is TypedMst.Variable -> arguments.getValue(symbol) -} - -/** - * Interprets the [TypedMst] node with this [Algebra] and optional [arguments]. - */ -public fun TypedMst.interpret(algebra: Algebra, vararg arguments: Pair): T = interpret( - algebra, - when (arguments.size) { - 0 -> emptyMap() - 1 -> mapOf(arguments[0]) - else -> hashMapOf(*arguments) - }, -) - -/** - * Interpret this [TypedMst] node as expression. - */ -public fun TypedMst.toExpression(algebra: Algebra): Expression = Expression { arguments -> - interpret(algebra, arguments) -} diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt deleted file mode 100644 index 8fc5a6aaf..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbolOrNull - -/** - * Evaluates constants in given [MST] for given [algebra] at the same time with converting to [TypedMst]. - */ -public fun MST.evaluateConstants(algebra: Algebra): TypedMst = when (this) { - is MST.Numeric -> TypedMst.Constant( - (algebra as? NumericAlgebra)?.number(value) ?: error("Numeric nodes are not supported by $algebra"), - value, - ) - - is MST.Unary -> when (val arg = value.evaluateConstants(algebra)) { - is TypedMst.Constant -> { - val value = algebra.unaryOperation( - operation, - arg.value, - ) - - TypedMst.Constant(value, if (value is Number) value else null) - } - - else -> TypedMst.Unary(operation, algebra.unaryOperationFunction(operation), arg) - } - - is MST.Binary -> { - val left = left.evaluateConstants(algebra) - val right = right.evaluateConstants(algebra) - - when { - left is TypedMst.Constant && right is TypedMst.Constant -> { - val value = when { - algebra is NumericAlgebra && left.number != null -> algebra.leftSideNumberOperation( - operation, - left.number, - right.value, - ) - - algebra is NumericAlgebra && right.number != null -> algebra.rightSideNumberOperation( - operation, - left.value, - right.number, - ) - - else -> algebra.binaryOperation( - operation, - left.value, - right.value, - ) - } - - TypedMst.Constant(value, if (value is Number) value else null) - } - - algebra is NumericAlgebra && left is TypedMst.Constant && left.number != null -> TypedMst.Binary( - operation, - algebra.leftSideNumberOperationFunction(operation), - left, - right, - ) - - algebra is NumericAlgebra && right is TypedMst.Constant && right.number != null -> TypedMst.Binary( - operation, - algebra.rightSideNumberOperationFunction(operation), - left, - right, - ) - - else -> TypedMst.Binary(operation, algebra.binaryOperationFunction(operation), left, right) - } - } - - is Symbol -> { - val boundSymbol = algebra.bindSymbolOrNull(this) - - if (boundSymbol != null) - TypedMst.Constant(boundSymbol, if (boundSymbol is Number) boundSymbol else null) - else - TypedMst.Variable(this) - } -} diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt index 5a338afed..34230f3c8 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -24,7 +24,7 @@ package space.kscience.kmath.ast.rendering * @author Iaroslav Postovalov */ public object LatexSyntaxRenderer : SyntaxRenderer { - override fun render(node: MathSyntax, output: Appendable): Unit = output.run { + public override fun render(node: MathSyntax, output: Appendable): Unit = output.run { fun render(syntax: MathSyntax) = render(syntax, output) when (node) { @@ -71,15 +71,6 @@ public object LatexSyntaxRenderer : SyntaxRenderer { append('}') } - is ExponentSyntax -> if (node.useOperatorForm) { - append("\\operatorname{exp}\\,") - render(node.operand) - } else { - append("e^{") - render(node.operand) - append('}') - } - is SuperscriptSyntax -> { render(node.left) append("^{") @@ -115,11 +106,7 @@ public object LatexSyntaxRenderer : SyntaxRenderer { render(node.right) } - is FractionSyntax -> if (node.infix) { - render(node.left) - append('/') - render(node.right) - } else { + is FractionSyntax -> { append("\\frac{") render(node.left) append("}{") diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt index bfd9aeef9..f7487a356 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -13,16 +13,13 @@ package space.kscience.kmath.ast.rendering * @author Iaroslav Postovalov */ public object MathMLSyntaxRenderer : SyntaxRenderer { - override fun render(node: MathSyntax, output: Appendable) { - output.append("") - renderPart(node, output) + public override fun render(node: MathSyntax, output: Appendable) { + output.append("") + render0(node, output) output.append("") } - /** - * Renders a part of syntax returning a correct MathML tag not the whole MathML instance. - */ - public fun renderPart(node: MathSyntax, output: Appendable): Unit = output.run { + private fun render0(node: MathSyntax, output: Appendable): Unit = output.run { fun tag(tagName: String, vararg attr: Pair, block: () -> Unit = {}) { append('<') append(tagName) @@ -47,7 +44,7 @@ public object MathMLSyntaxRenderer : SyntaxRenderer { append('>') } - fun render(syntax: MathSyntax) = renderPart(syntax, output) + fun render(syntax: MathSyntax) = render0(syntax, output) when (node) { is NumberSyntax -> tag("mn") { append(node.string) } @@ -85,19 +82,6 @@ public object MathMLSyntaxRenderer : SyntaxRenderer { is RadicalSyntax -> tag("msqrt") { render(node.operand) } - is ExponentSyntax -> if (node.useOperatorForm) { - tag("mo") { append("exp") } - tag("mspace", "width" to "0.167em") - render(node.operand) - } else { - tag("msup") { - tag("mrow") { - tag("mi") { append("e") } - } - tag("mrow") { render(node.operand) } - } - } - is SuperscriptSyntax -> tag("msup") { tag("mrow") { render(node.left) } tag("mrow") { render(node.right) } @@ -130,13 +114,14 @@ public object MathMLSyntaxRenderer : SyntaxRenderer { render(node.right) } - is FractionSyntax -> if (node.infix) { - render(node.left) - tag("mo") { append('/') } - render(node.right) - } else tag("mfrac") { - tag("mrow") { render(node.left) } - tag("mrow") { render(node.right) } + is FractionSyntax -> tag("mfrac") { + tag("mrow") { + render(node.left) + } + + tag("mrow") { + render(node.right) + } } is RadicalWithIndexSyntax -> tag("mroot") { diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt index f88a5b319..891e8f05b 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -26,7 +26,7 @@ public fun interface MathRenderer { * @author Iaroslav Postovalov */ public open class FeaturedMathRenderer(public val features: List) : MathRenderer { - override fun render(mst: MST): MathSyntax { + public override fun render(mst: MST): MathSyntax { for (feature in features) feature.render(this, mst)?.let { return it } throw UnsupportedOperationException("Renderer $this has no appropriate feature to render node $mst.") } @@ -50,9 +50,9 @@ public open class FeaturedMathRenderer(public val features: List) */ public open class FeaturedMathRendererWithPostProcess( features: List, - public val stages: List, + public val stages: List, ) : FeaturedMathRenderer(features) { - override fun render(mst: MST): MathSyntax { + public override fun render(mst: MST): MathSyntax { val res = super.render(mst) for (stage in stages) stage.perform(res) return res @@ -61,7 +61,7 @@ public open class FeaturedMathRendererWithPostProcess( /** * Logical unit of [MathSyntax] post-processing. */ - public fun interface PostProcessPhase { + public fun interface PostProcessStage { /** * Performs the specified action over [MathSyntax]. */ @@ -83,9 +83,8 @@ public open class FeaturedMathRendererWithPostProcess( Fraction.Default, Power.Default, SquareRoot.Default, - Exponent.Default, + Exponential.Default, InverseTrigonometricOperations.Default, - InverseHyperbolicOperations.Default, // Fallback option for unknown operations - printing them as operator BinaryOperator.Default, @@ -98,11 +97,9 @@ public open class FeaturedMathRendererWithPostProcess( // Printing terminal nodes as string PrintNumeric, - PrintSymbol, + PrintSymbolic, ), listOf( - BetterExponent, - BetterFraction, SimplifyParentheses.Default, BetterMultiplication, ), diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt index 0196be3b6..069e56c71 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt @@ -1,12 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ast.rendering /** - * Syntax node for mathematical typography. + * Mathematical typography syntax node. * * @author Iaroslav Postovalov */ @@ -92,7 +92,7 @@ public data class SymbolSyntax(public var string: String) : TerminalSyntax() public data class OperatorNameSyntax(public var name: String) : TerminalSyntax() /** - * Represents a usage of special symbols (e.g., *∞*). + * Represents a usage of special symbols. * * @property kind The kind of symbol. * @author Iaroslav Postovalov @@ -131,15 +131,15 @@ public data class OperandSyntax( } /** - * Represents unary, prefix operator syntax (like *f(x)*). + * Represents unary, prefix operator syntax (like f x). * * @property prefix The prefix. * @author Iaroslav Postovalov */ public data class UnaryOperatorSyntax( - override val operation: String, + public override val operation: String, public var prefix: MathSyntax, - override val operand: OperandSyntax, + public override val operand: OperandSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -147,13 +147,13 @@ public data class UnaryOperatorSyntax( } /** - * Represents prefix, unary plus operator (*+x*). + * Represents prefix, unary plus operator. * * @author Iaroslav Postovalov */ public data class UnaryPlusSyntax( - override val operation: String, - override val operand: OperandSyntax, + public override val operation: String, + public override val operand: OperandSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -161,13 +161,13 @@ public data class UnaryPlusSyntax( } /** - * Represents prefix, unary minus operator (*-x*). + * Represents prefix, unary minus operator. * * @author Iaroslav Postovalov */ public data class UnaryMinusSyntax( - override val operation: String, - override val operand: OperandSyntax, + public override val operation: String, + public override val operand: OperandSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -175,14 +175,14 @@ public data class UnaryMinusSyntax( } /** - * Represents radical with a node inside it (*√x*). + * Represents radical with a node inside it. * * @property operand The radicand. * @author Iaroslav Postovalov */ public data class RadicalSyntax( - override val operation: String, - override val operand: MathSyntax, + public override val operation: String, + public override val operand: MathSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -190,34 +190,16 @@ public data class RadicalSyntax( } /** - * Represents exponential function. - * - * @property operand The argument of function. - * @property useOperatorForm `true` if operator form is used (*exp (x)*), `false` if exponentiation form is used - * (*ex*). - * @author Iaroslav Postovalov - */ -public data class ExponentSyntax( - override val operation: String, - override val operand: OperandSyntax, - public var useOperatorForm: Boolean, -) : UnarySyntax() { - init { - operand.parent = this - } -} - -/** - * Represents a syntax node with superscript (*x2*). + * Represents a syntax node with superscript (usually, for exponentiation). * * @property left The node. * @property right The superscript. * @author Iaroslav Postovalov */ public data class SuperscriptSyntax( - override val operation: String, - override val left: MathSyntax, - override val right: MathSyntax, + public override val operation: String, + public override val left: MathSyntax, + public override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -226,16 +208,16 @@ public data class SuperscriptSyntax( } /** - * Represents a syntax node with subscript (*x
i*). + * Represents a syntax node with subscript. * * @property left The node. * @property right The subscript. * @author Iaroslav Postovalov */ public data class SubscriptSyntax( - override val operation: String, - override val left: MathSyntax, - override val right: MathSyntax, + public override val operation: String, + public override val left: MathSyntax, + public override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -244,16 +226,16 @@ public data class SubscriptSyntax( } /** - * Represents binary, prefix operator syntax (like *f(a, b)*). + * Represents binary, prefix operator syntax (like f(a, b)). * * @property prefix The prefix. * @author Iaroslav Postovalov */ public data class BinaryOperatorSyntax( - override val operation: String, + public override val operation: String, public var prefix: MathSyntax, - override val left: MathSyntax, - override val right: MathSyntax, + public override val left: MathSyntax, + public override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -262,16 +244,16 @@ public data class BinaryOperatorSyntax( } /** - * Represents binary, infix addition (*42 + 42*). + * Represents binary, infix addition. * * @param left The augend. * @param right The addend. * @author Iaroslav Postovalov */ public data class BinaryPlusSyntax( - override val operation: String, - override val left: OperandSyntax, - override val right: OperandSyntax, + public override val operation: String, + public override val left: OperandSyntax, + public override val right: OperandSyntax, ) : BinarySyntax() { init { left.parent = this @@ -280,16 +262,16 @@ public data class BinaryPlusSyntax( } /** - * Represents binary, infix subtraction (*42 − 42*). + * Represents binary, infix subtraction. * * @param left The minuend. * @param right The subtrahend. * @author Iaroslav Postovalov */ public data class BinaryMinusSyntax( - override val operation: String, - override val left: OperandSyntax, - override val right: OperandSyntax, + public override val operation: String, + public override val left: OperandSyntax, + public override val right: OperandSyntax, ) : BinarySyntax() { init { left.parent = this @@ -302,14 +284,12 @@ public data class BinaryMinusSyntax( * * @property left The numerator. * @property right The denominator. - * @property infix Whether infix (*1 / 2*) or normal (*½*) fraction should be made. * @author Iaroslav Postovalov */ public data class FractionSyntax( - override val operation: String, - override val left: OperandSyntax, - override val right: OperandSyntax, - public var infix: Boolean, + public override val operation: String, + public override val left: MathSyntax, + public override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -318,16 +298,16 @@ public data class FractionSyntax( } /** - * Represents radical syntax with index (*3√x*). + * Represents radical syntax with index. * * @property left The index. * @property right The radicand. * @author Iaroslav Postovalov */ public data class RadicalWithIndexSyntax( - override val operation: String, - override val left: MathSyntax, - override val right: MathSyntax, + public override val operation: String, + public override val left: MathSyntax, + public override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -336,17 +316,17 @@ public data class RadicalWithIndexSyntax( } /** - * Represents binary, infix multiplication in the form of coefficient (*2 x*) or with operator (*x × 2*). + * Represents binary, infix multiplication in the form of coefficient (2 x) or with operator (x×2). * * @property left The multiplicand. * @property right The multiplier. - * @property times Whether the times (×) symbol should be used. + * @property times whether the times (×) symbol should be used. * @author Iaroslav Postovalov */ public data class MultiplicationSyntax( - override val operation: String, - override val left: OperandSyntax, - override val right: OperandSyntax, + public override val operation: String, + public override val left: OperandSyntax, + public override val right: OperandSyntax, public var times: Boolean, ) : BinarySyntax() { init { diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt index 16957bdd2..7fa91e158 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,7 +7,7 @@ package space.kscience.kmath.ast.rendering /** * Abstraction of writing [MathSyntax] as a string of an actual markup language. Typical implementation should - * involve traversal of MathSyntax with handling each subtype. + * involve traversal of MathSyntax with handling each its subtype. * * @author Iaroslav Postovalov */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt index 4deffc83c..5d6c7bb0a 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,18 +7,19 @@ package space.kscience.kmath.ast.rendering import space.kscience.kmath.ast.rendering.FeaturedMathRenderer.RenderFeature import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.* import kotlin.reflect.KClass /** - * Prints any [Symbol] as a [SymbolSyntax] containing the [Symbol.identity] of it. + * Prints any [MST.Symbolic] as a [SymbolSyntax] containing the [MST.Symbolic.value] of it. * * @author Iaroslav Postovalov */ -public val PrintSymbol: RenderFeature = RenderFeature { _, node -> - if (node !is Symbol) null - else SymbolSyntax(string = node.identity) +public object PrintSymbolic : RenderFeature { + public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { + if (node !is MST.Symbolic) return null + return SymbolSyntax(string = node.value) + } } /** @@ -26,48 +27,44 @@ public val PrintSymbol: RenderFeature = RenderFeature { _, node -> * * @author Iaroslav Postovalov */ -public val PrintNumeric: RenderFeature = RenderFeature { _, node -> - if (node !is MST.Numeric) - null - else - NumberSyntax(string = node.value.toString()) +public object PrintNumeric : RenderFeature { + public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { + if (node !is MST.Numeric) return null + return NumberSyntax(string = node.value.toString()) + } } -private fun printSignedNumberString(s: String): MathSyntax = if (s.startsWith('-')) - UnaryMinusSyntax( - operation = GroupOps.MINUS_OPERATION, - operand = OperandSyntax( - operand = NumberSyntax(string = s.removePrefix("-")), - parentheses = true, - ), - ) -else - NumberSyntax(string = s) +private fun printSignedNumberString(s: String): MathSyntax { + if (s.startsWith('-')) + return UnaryMinusSyntax( + operation = GroupOperations.MINUS_OPERATION, + operand = OperandSyntax( + operand = NumberSyntax(string = s.removePrefix("-")), + parentheses = true, + ), + ) + + return NumberSyntax(string = s) +} /** - * Special printing for numeric types that are printed in form of + * Special printing for numeric types which are printed in form of * *('-'? (DIGIT+ ('.' DIGIT+)? ('E' '-'? DIGIT+)? | 'Infinity')) | 'NaN'*. * * @property types The suitable types. - * @author Iaroslav Postovalov */ public class PrettyPrintFloats(public val types: Set>) : RenderFeature { - override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { + public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { if (node !is MST.Numeric || node.value::class !in types) return null + val toString = node.value.toString().removeSuffix(".0") - val toString = when (val v = node.value) { - is Float -> v.multiplatformToString() - is Double -> v.multiplatformToString() - else -> v.toString() - }.removeSuffix(".0") - - if (toString.contains('E', ignoreCase = true)) { - val (beforeE, afterE) = toString.split('E', ignoreCase = true) + if ('E' in toString) { + val (beforeE, afterE) = toString.split('E') val significand = beforeE.toDouble().toString().removeSuffix(".0") val exponent = afterE.toDouble().toString().removeSuffix(".0") return MultiplicationSyntax( - operation = RingOps.TIMES_OPERATION, + operation = RingOperations.TIMES_OPERATION, left = OperandSyntax(operand = NumberSyntax(significand), parentheses = true), right = OperandSyntax( operand = SuperscriptSyntax( @@ -86,7 +83,7 @@ public class PrettyPrintFloats(public val types: Set>) : Rend if (toString.startsWith('-')) return UnaryMinusSyntax( - operation = GroupOps.MINUS_OPERATION, + operation = GroupOperations.MINUS_OPERATION, operand = OperandSyntax(operand = infty, parentheses = true), ) @@ -105,17 +102,17 @@ public class PrettyPrintFloats(public val types: Set>) : Rend } /** - * Special printing for numeric types that are printed in form of *'-'? DIGIT+*. + * Special printing for numeric types which are printed in form of *'-'? DIGIT+*. * * @property types The suitable types. - * @author Iaroslav Postovalov */ public class PrettyPrintIntegers(public val types: Set>) : RenderFeature { - override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = + public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { if (node !is MST.Numeric || node.value::class !in types) - null - else - printSignedNumberString(node.value.toString()) + return null + + return printSignedNumberString(node.value.toString()) + } public companion object { /** @@ -130,14 +127,12 @@ public class PrettyPrintIntegers(public val types: Set>) : Re * Special printing for symbols meaning Pi. * * @property symbols The allowed symbols. - * @author Iaroslav Postovalov */ public class PrettyPrintPi(public val symbols: Set) : RenderFeature { - override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = - if (node !is Symbol || node.identity !in symbols) - null - else - SpecialSymbolSyntax(kind = SpecialSymbolSyntax.Kind.SMALL_PI) + public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { + if (node !is MST.Symbolic || node.value !in symbols) return null + return SpecialSymbolSyntax(kind = SpecialSymbolSyntax.Kind.SMALL_PI) + } public companion object { /** @@ -148,311 +143,191 @@ public class PrettyPrintPi(public val symbols: Set) : RenderFeature { } /** - * Abstract printing of unary operations that discards [MST] if their operation is not in [operations] or its type is + * Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is * not [MST.Unary]. * * @param operations the allowed operations. If `null`, any operation is accepted. - * @author Iaroslav Postovalov */ public abstract class Unary(public val operations: Collection?) : RenderFeature { /** - * The actual render function specialized for [MST.Unary]. + * The actual render function. */ - protected abstract fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax? + protected abstract fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax? - public final override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = - if (node !is MST.Unary || operations != null && node.operation !in operations) - null - else - renderUnary(renderer, node) + public final override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { + if (node !is MST.Unary || operations != null && node.operation !in operations) return null + return render0(renderer, node) + } } /** - * Abstract printing of unary operations that discards [MST] if their operation is not in [operations] or its type is + * Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is * not [MST.Binary]. * * @property operations the allowed operations. If `null`, any operation is accepted. - * @author Iaroslav Postovalov */ public abstract class Binary(public val operations: Collection?) : RenderFeature { /** - * The actual render function specialized for [MST.Binary]. + * The actual render function. */ - protected abstract fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax? + protected abstract fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax? public final override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { if (node !is MST.Binary || operations != null && node.operation !in operations) return null - return renderBinary(renderer, node) + return render0(renderer, node) } } -/** - * Handles binary nodes by producing [BinaryPlusSyntax]. - * - * @author Iaroslav Postovalov - */ public class BinaryPlus(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - BinaryPlusSyntax( - operation = node.operation, - left = OperandSyntax(parent.render(node.left), true), - right = OperandSyntax(parent.render(node.right), true), - ) + public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryPlusSyntax( + operation = node.operation, + left = OperandSyntax(parent.render(node.left), true), + right = OperandSyntax(parent.render(node.right), true), + ) public companion object { - /** - * The default instance configured with [GroupOps.PLUS_OPERATION]. - */ - public val Default: BinaryPlus = BinaryPlus(setOf(GroupOps.PLUS_OPERATION)) + public val Default: BinaryPlus = BinaryPlus(setOf(GroupOperations.PLUS_OPERATION)) } } -/** - * Handles binary nodes by producing [BinaryMinusSyntax]. - * - * @author Iaroslav Postovalov - */ public class BinaryMinus(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - BinaryMinusSyntax( - operation = node.operation, - left = OperandSyntax(operand = parent.render(node.left), parentheses = true), - right = OperandSyntax(operand = parent.render(node.right), parentheses = true), - ) - - public companion object { - /** - * The default instance configured with [GroupOps.MINUS_OPERATION]. - */ - public val Default: BinaryMinus = BinaryMinus(setOf(GroupOps.MINUS_OPERATION)) - } -} - -/** - * Handles unary nodes by producing [UnaryPlusSyntax]. - * - * @author Iaroslav Postovalov - */ -public class UnaryPlus(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryPlusSyntax( - operation = node.operation, - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - ) - - public companion object { - /** - * The default instance configured with [GroupOps.PLUS_OPERATION]. - */ - public val Default: UnaryPlus = UnaryPlus(setOf(GroupOps.PLUS_OPERATION)) - } -} - -/** - * Handles binary nodes by producing [UnaryMinusSyntax]. - * - * @author Iaroslav Postovalov - */ -public class UnaryMinus(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryMinusSyntax( - operation = node.operation, - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - ) - - public companion object { - /** - * The default instance configured with [GroupOps.MINUS_OPERATION]. - */ - public val Default: UnaryMinus = UnaryMinus(setOf(GroupOps.MINUS_OPERATION)) - } -} - -/** - * Handles binary nodes by producing [FractionSyntax]. - * - * @author Iaroslav Postovalov - */ -public class Fraction(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = FractionSyntax( + public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryMinusSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), right = OperandSyntax(operand = parent.render(node.right), parentheses = true), - infix = true, ) public companion object { - /** - * The default instance configured with [FieldOps.DIV_OPERATION]. - */ - public val Default: Fraction = Fraction(setOf(FieldOps.DIV_OPERATION)) + public val Default: BinaryMinus = BinaryMinus(setOf(GroupOperations.MINUS_OPERATION)) } } -/** - * Handles binary nodes by producing [BinaryOperatorSyntax]. - * - * @author Iaroslav Postovalov - */ -public class BinaryOperator(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - BinaryOperatorSyntax( - operation = node.operation, - prefix = OperatorNameSyntax(name = node.operation), - left = parent.render(node.left), - right = parent.render(node.right), - ) +public class UnaryPlus(operations: Collection?) : Unary(operations) { + public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryPlusSyntax( + operation = node.operation, + operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), + ) + + public companion object { + public val Default: UnaryPlus = UnaryPlus(setOf(GroupOperations.PLUS_OPERATION)) + } +} + +public class UnaryMinus(operations: Collection?) : Unary(operations) { + public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryMinusSyntax( + operation = node.operation, + operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), + ) + + public companion object { + public val Default: UnaryMinus = UnaryMinus(setOf(GroupOperations.MINUS_OPERATION)) + } +} + +public class Fraction(operations: Collection?) : Binary(operations) { + public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = FractionSyntax( + operation = node.operation, + left = parent.render(node.left), + right = parent.render(node.right), + ) + + public companion object { + public val Default: Fraction = Fraction(setOf(FieldOperations.DIV_OPERATION)) + } +} + +public class BinaryOperator(operations: Collection?) : Binary(operations) { + public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryOperatorSyntax( + operation = node.operation, + prefix = OperatorNameSyntax(name = node.operation), + left = parent.render(node.left), + right = parent.render(node.right), + ) public companion object { - /** - * The default instance configured with `null`. - */ public val Default: BinaryOperator = BinaryOperator(null) } } -/** - * Handles unary nodes by producing [UnaryOperatorSyntax]. - * - * @author Iaroslav Postovalov - */ public class UnaryOperator(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = - UnaryOperatorSyntax( - operation = node.operation, - prefix = OperatorNameSyntax(node.operation), - operand = OperandSyntax(parent.render(node.value), true), - ) + public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( + operation = node.operation, + prefix = OperatorNameSyntax(node.operation), + operand = OperandSyntax(parent.render(node.value), true), + ) public companion object { - /** - * The default instance configured with `null`. - */ public val Default: UnaryOperator = UnaryOperator(null) } } -/** - * Handles binary nodes by producing [SuperscriptSyntax]. - * - * @author Iaroslav Postovalov - */ public class Power(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - SuperscriptSyntax( - operation = node.operation, - left = OperandSyntax(parent.render(node.left), true), - right = OperandSyntax(parent.render(node.right), true), - ) + public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = SuperscriptSyntax( + operation = node.operation, + left = OperandSyntax(parent.render(node.left), true), + right = OperandSyntax(parent.render(node.right), true), + ) public companion object { - /** - * The default instance configured with [PowerOperations.POW_OPERATION]. - */ public val Default: Power = Power(setOf(PowerOperations.POW_OPERATION)) } } -/** - * Handles binary nodes by producing [RadicalSyntax] with no index. - */ public class SquareRoot(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = + public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = RadicalSyntax(operation = node.operation, operand = parent.render(node.value)) public companion object { - /** - * The default instance configured with [PowerOperations.SQRT_OPERATION]. - */ public val Default: SquareRoot = SquareRoot(setOf(PowerOperations.SQRT_OPERATION)) } } -/** - * Handles unary nodes by producing [ExponentSyntax]. - * - * @author Iaroslav Postovalov - */ -public class Exponent(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = ExponentSyntax( +public class Exponential(operations: Collection?) : Unary(operations) { + public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = SuperscriptSyntax( operation = node.operation, - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - useOperatorForm = true, + left = SymbolSyntax(string = "e"), + right = parent.render(node.value), ) public companion object { - /** - * The default instance configured with [ExponentialOperations.EXP_OPERATION]. - */ - public val Default: Exponent = Exponent(setOf(ExponentialOperations.EXP_OPERATION)) + public val Default: Exponential = Exponential(setOf(ExponentialOperations.EXP_OPERATION)) } } -/** - * Handles binary nodes by producing [MultiplicationSyntax]. - * - * @author Iaroslav Postovalov - */ public class Multiplication(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - MultiplicationSyntax( - operation = node.operation, - left = OperandSyntax(operand = parent.render(node.left), parentheses = true), - right = OperandSyntax(operand = parent.render(node.right), parentheses = true), - times = true, - ) + public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = MultiplicationSyntax( + operation = node.operation, + left = OperandSyntax(operand = parent.render(node.left), parentheses = true), + right = OperandSyntax(operand = parent.render(node.right), parentheses = true), + times = true, + ) public companion object { - /** - * The default instance configured with [RingOps.TIMES_OPERATION]. - */ - public val Default: Multiplication = Multiplication(setOf(RingOps.TIMES_OPERATION)) - } -} - -/** - * Handles binary nodes by producing inverse [UnaryOperatorSyntax] with *arc* prefix instead of *a*. - * - * @author Iaroslav Postovalov - */ -public class InverseTrigonometricOperations(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = - UnaryOperatorSyntax( - operation = node.operation, - prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "arc")), - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - ) - - public companion object { - /** - * The default instance configured with [TrigonometricOperations.ACOS_OPERATION], - * [TrigonometricOperations.ASIN_OPERATION], [TrigonometricOperations.ATAN_OPERATION]. - */ - public val Default: InverseTrigonometricOperations = InverseTrigonometricOperations(setOf( - TrigonometricOperations.ACOS_OPERATION, - TrigonometricOperations.ASIN_OPERATION, - TrigonometricOperations.ATAN_OPERATION, + public val Default: Multiplication = Multiplication(setOf( + RingOperations.TIMES_OPERATION, )) } } -/** - * Handles binary nodes by producing inverse [UnaryOperatorSyntax] with *ar* prefix instead of *a*. - * - * @author Iaroslav Postovalov - */ -public class InverseHyperbolicOperations(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = - UnaryOperatorSyntax( - operation = node.operation, - prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "ar")), - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - ) +public class InverseTrigonometricOperations(operations: Collection?) : Unary(operations) { + public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( + operation = node.operation, + prefix = SuperscriptSyntax( + operation = PowerOperations.POW_OPERATION, + left = OperatorNameSyntax(name = node.operation.removePrefix("a")), + right = UnaryMinusSyntax( + operation = GroupOperations.MINUS_OPERATION, + operand = OperandSyntax(operand = NumberSyntax(string = "1"), parentheses = true), + ), + ), + operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), + ) public companion object { - /** - * The default instance configured with [ExponentialOperations.ACOSH_OPERATION], - * [ExponentialOperations.ASINH_OPERATION], and [ExponentialOperations.ATANH_OPERATION]. - */ - public val Default: InverseHyperbolicOperations = InverseHyperbolicOperations(setOf( + public val Default: InverseTrigonometricOperations = InverseTrigonometricOperations(setOf( + TrigonometricOperations.ACOS_OPERATION, + TrigonometricOperations.ASIN_OPERATION, + TrigonometricOperations.ATAN_OPERATION, ExponentialOperations.ACOSH_OPERATION, ExponentialOperations.ASINH_OPERATION, ExponentialOperations.ATANH_OPERATION, diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt deleted file mode 100644 index dce99cc5a..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast.rendering - -internal expect fun Double.multiplatformToString(): String -internal expect fun Float.multiplatformToString(): String diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt deleted file mode 100644 index 0d26621d3..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess.PostProcessPhase -import space.kscience.kmath.operations.FieldOps -import space.kscience.kmath.operations.GroupOps -import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.RingOps - -/** - * Removes unnecessary times (×) symbols from [MultiplicationSyntax]. - * - * @author Iaroslav Postovalov - */ -public val BetterMultiplication: PostProcessPhase = PostProcessPhase { node -> - fun perform(node: MathSyntax): Unit = when (node) { - is NumberSyntax -> Unit - is SymbolSyntax -> Unit - is OperatorNameSyntax -> Unit - is SpecialSymbolSyntax -> Unit - is OperandSyntax -> perform(node.operand) - - is UnaryOperatorSyntax -> { - perform(node.prefix) - perform(node.operand) - } - - is UnaryPlusSyntax -> perform(node.operand) - is UnaryMinusSyntax -> perform(node.operand) - is RadicalSyntax -> perform(node.operand) - is ExponentSyntax -> perform(node.operand) - - is SuperscriptSyntax -> { - perform(node.left) - perform(node.right) - } - - is SubscriptSyntax -> { - perform(node.left) - perform(node.right) - } - - is BinaryOperatorSyntax -> { - perform(node.prefix) - perform(node.left) - perform(node.right) - } - - is BinaryPlusSyntax -> { - perform(node.left) - perform(node.right) - } - - is BinaryMinusSyntax -> { - perform(node.left) - perform(node.right) - } - - is FractionSyntax -> { - perform(node.left) - perform(node.right) - } - - is RadicalWithIndexSyntax -> { - perform(node.left) - perform(node.right) - } - - is MultiplicationSyntax -> { - node.times = node.right.operand is NumberSyntax && !node.right.parentheses - || node.left.operand is NumberSyntax && node.right.operand is FractionSyntax - || node.left.operand is NumberSyntax && node.right.operand is NumberSyntax - || node.left.operand is NumberSyntax && node.right.operand is SuperscriptSyntax && node.right.operand.left is NumberSyntax - - perform(node.left) - perform(node.right) - } - } - - perform(node) -} - -/** - * Chooses [FractionSyntax.infix] depending on the context. - * - * @author Iaroslav Postovalov - */ -public val BetterFraction: PostProcessPhase = PostProcessPhase { node -> - fun perform(node: MathSyntax, infix: Boolean = false): Unit = when (node) { - is NumberSyntax -> Unit - is SymbolSyntax -> Unit - is OperatorNameSyntax -> Unit - is SpecialSymbolSyntax -> Unit - is OperandSyntax -> perform(node.operand, infix) - - is UnaryOperatorSyntax -> { - perform(node.prefix, infix) - perform(node.operand, infix) - } - - is UnaryPlusSyntax -> perform(node.operand, infix) - is UnaryMinusSyntax -> perform(node.operand, infix) - is RadicalSyntax -> perform(node.operand, infix) - is ExponentSyntax -> perform(node.operand, infix) - - is SuperscriptSyntax -> { - perform(node.left, true) - perform(node.right, true) - } - - is SubscriptSyntax -> { - perform(node.left, true) - perform(node.right, true) - } - - is BinaryOperatorSyntax -> { - perform(node.prefix, infix) - perform(node.left, infix) - perform(node.right, infix) - } - - is BinaryPlusSyntax -> { - perform(node.left, infix) - perform(node.right, infix) - } - - is BinaryMinusSyntax -> { - perform(node.left, infix) - perform(node.right, infix) - } - - is FractionSyntax -> { - node.infix = infix - perform(node.left, infix) - perform(node.right, infix) - } - - is RadicalWithIndexSyntax -> { - perform(node.left, true) - perform(node.right, true) - } - - is MultiplicationSyntax -> { - perform(node.left, infix) - perform(node.right, infix) - } - } - - perform(node) -} - -/** - * Applies [ExponentSyntax.useOperatorForm] to [ExponentSyntax] when the operand contains a fraction, a - * superscript or a subscript to improve readability. - * - * @author Iaroslav Postovalov - */ -public val BetterExponent: PostProcessPhase = PostProcessPhase { node -> - fun perform(node: MathSyntax): Boolean { - return when (node) { - is NumberSyntax -> false - is SymbolSyntax -> false - is OperatorNameSyntax -> false - is SpecialSymbolSyntax -> false - is OperandSyntax -> perform(node.operand) - is UnaryOperatorSyntax -> perform(node.prefix) || perform(node.operand) - is UnaryPlusSyntax -> perform(node.operand) - is UnaryMinusSyntax -> perform(node.operand) - is RadicalSyntax -> true - - is ExponentSyntax -> { - val r = perform(node.operand) - node.useOperatorForm = r - r - } - - is SuperscriptSyntax -> true - is SubscriptSyntax -> true - is BinaryOperatorSyntax -> perform(node.prefix) || perform(node.left) || perform(node.right) - is BinaryPlusSyntax -> perform(node.left) || perform(node.right) - is BinaryMinusSyntax -> perform(node.left) || perform(node.right) - is FractionSyntax -> true - is RadicalWithIndexSyntax -> true - is MultiplicationSyntax -> perform(node.left) || perform(node.right) - } - } - - perform(node) -} - -/** - * Removes unnecessary parentheses from [OperandSyntax]. - * - * @property precedenceFunction Returns the precedence number for syntax node. Higher number is lower priority. - * @author Iaroslav Postovalov - */ -public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) : - PostProcessPhase { - override fun perform(node: MathSyntax): Unit = when (node) { - is NumberSyntax -> Unit - is SymbolSyntax -> Unit - is OperatorNameSyntax -> Unit - is SpecialSymbolSyntax -> Unit - - is OperandSyntax -> { - val isRightOfSuperscript = - (node.parent is SuperscriptSyntax) && (node.parent as SuperscriptSyntax).right === node - - val precedence = precedenceFunction(node.operand) - - val needParenthesesByPrecedence = when (val parent = node.parent) { - null -> false - - is BinarySyntax -> { - val parentPrecedence = precedenceFunction(parent) - - parentPrecedence < precedence || - parentPrecedence == precedence && parentPrecedence != 0 && node === parent.right - } - - else -> precedence > precedenceFunction(parent) - } - - val isInsideExpOperator = - node.parent is ExponentSyntax && (node.parent as ExponentSyntax).useOperatorForm - - val isOnOrUnderNormalFraction = node.parent is FractionSyntax && !((node.parent as FractionSyntax).infix) - - node.parentheses = !isRightOfSuperscript - && (needParenthesesByPrecedence || node.parent is UnaryOperatorSyntax || isInsideExpOperator) - && !isOnOrUnderNormalFraction - - perform(node.operand) - } - - is UnaryOperatorSyntax -> { - perform(node.prefix) - perform(node.operand) - } - - is UnaryPlusSyntax -> perform(node.operand) - is UnaryMinusSyntax -> perform(node.operand) - is RadicalSyntax -> perform(node.operand) - is ExponentSyntax -> perform(node.operand) - - is SuperscriptSyntax -> { - perform(node.left) - perform(node.right) - } - - is SubscriptSyntax -> { - perform(node.left) - perform(node.right) - } - - is BinaryOperatorSyntax -> { - perform(node.prefix) - perform(node.left) - perform(node.right) - } - - is BinaryPlusSyntax -> { - perform(node.left) - perform(node.right) - } - - is BinaryMinusSyntax -> { - perform(node.left) - perform(node.right) - } - - is FractionSyntax -> { - perform(node.left) - perform(node.right) - } - - is MultiplicationSyntax -> { - perform(node.left) - perform(node.right) - } - - is RadicalWithIndexSyntax -> { - perform(node.left) - perform(node.right) - } - } - - public companion object { - /** - * The default configuration of [SimplifyParentheses] where power is 1, multiplicative operations are 2, - * additive operations are 3. - */ - public val Default: SimplifyParentheses = SimplifyParentheses { - when (it) { - is TerminalSyntax -> 0 - is UnarySyntax -> 2 - - is BinarySyntax -> when (it.operation) { - PowerOperations.POW_OPERATION -> 1 - RingOps.TIMES_OPERATION -> 3 - FieldOps.DIV_OPERATION -> 3 - GroupOps.MINUS_OPERATION -> 4 - GroupOps.PLUS_OPERATION -> 4 - else -> 0 - } - - else -> 0 - } - } - } -} diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt new file mode 100644 index 000000000..0ebb41b28 --- /dev/null +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt @@ -0,0 +1,202 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.ast.rendering + +import space.kscience.kmath.operations.FieldOperations +import space.kscience.kmath.operations.GroupOperations +import space.kscience.kmath.operations.PowerOperations +import space.kscience.kmath.operations.RingOperations + +/** + * Removes unnecessary times (×) symbols from [MultiplicationSyntax]. + * + * @author Iaroslav Postovalov + */ +public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostProcessStage { + public override fun perform(node: MathSyntax) { + when (node) { + is NumberSyntax -> Unit + is SymbolSyntax -> Unit + is OperatorNameSyntax -> Unit + is SpecialSymbolSyntax -> Unit + is OperandSyntax -> perform(node.operand) + + is UnaryOperatorSyntax -> { + perform(node.prefix) + perform(node.operand) + } + + is UnaryPlusSyntax -> perform(node.operand) + is UnaryMinusSyntax -> perform(node.operand) + is RadicalSyntax -> perform(node.operand) + + is SuperscriptSyntax -> { + perform(node.left) + perform(node.right) + } + + is SubscriptSyntax -> { + perform(node.left) + perform(node.right) + } + + is BinaryOperatorSyntax -> { + perform(node.prefix) + perform(node.left) + perform(node.right) + } + + is BinaryPlusSyntax -> { + perform(node.left) + perform(node.right) + } + + is BinaryMinusSyntax -> { + perform(node.left) + perform(node.right) + } + + is FractionSyntax -> { + perform(node.left) + perform(node.right) + } + + is RadicalWithIndexSyntax -> { + perform(node.left) + perform(node.right) + } + + is MultiplicationSyntax -> { + node.times = node.right.operand is NumberSyntax && !node.right.parentheses + || node.left.operand is NumberSyntax && node.right.operand is FractionSyntax + || node.left.operand is NumberSyntax && node.right.operand is NumberSyntax + || node.left.operand is NumberSyntax && node.right.operand is SuperscriptSyntax && node.right.operand.left is NumberSyntax + + perform(node.left) + perform(node.right) + } + } + } +} + +/** + * Removes unnecessary parentheses from [OperandSyntax]. + * + * @property precedenceFunction Returns the precedence number for syntax node. Higher number is lower priority. + * @author Iaroslav Postovalov + */ +public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) : + FeaturedMathRendererWithPostProcess.PostProcessStage { + public override fun perform(node: MathSyntax) { + when (node) { + is NumberSyntax -> Unit + is SymbolSyntax -> Unit + is OperatorNameSyntax -> Unit + is SpecialSymbolSyntax -> Unit + + is OperandSyntax -> { + val isRightOfSuperscript = + (node.parent is SuperscriptSyntax) && (node.parent as SuperscriptSyntax).right === node + + val precedence = precedenceFunction(node.operand) + + val needParenthesesByPrecedence = when (val parent = node.parent) { + null -> false + + is BinarySyntax -> { + val parentPrecedence = precedenceFunction(parent) + + parentPrecedence < precedence || + parentPrecedence == precedence && parentPrecedence != 0 && node === parent.right + } + + else -> precedence > precedenceFunction(parent) + } + + node.parentheses = !isRightOfSuperscript + && (needParenthesesByPrecedence || node.parent is UnaryOperatorSyntax) + + perform(node.operand) + } + + is UnaryOperatorSyntax -> { + perform(node.prefix) + perform(node.operand) + } + + is UnaryPlusSyntax -> perform(node.operand) + is UnaryMinusSyntax -> { + perform(node.operand) + } + is RadicalSyntax -> perform(node.operand) + + is SuperscriptSyntax -> { + perform(node.left) + perform(node.right) + } + + is SubscriptSyntax -> { + perform(node.left) + perform(node.right) + } + + is BinaryOperatorSyntax -> { + perform(node.prefix) + perform(node.left) + perform(node.right) + } + + is BinaryPlusSyntax -> { + perform(node.left) + perform(node.right) + } + + is BinaryMinusSyntax -> { + perform(node.left) + perform(node.right) + } + + is FractionSyntax -> { + perform(node.left) + perform(node.right) + } + + is MultiplicationSyntax -> { + perform(node.left) + perform(node.right) + } + + is RadicalWithIndexSyntax -> { + perform(node.left) + perform(node.right) + } + } + } + + public companion object { + /** + * The default configuration of [SimplifyParentheses] where power is 1, multiplicative operations are 2, + * additive operations are 3. + */ + public val Default: SimplifyParentheses = SimplifyParentheses { + when (it) { + is TerminalSyntax -> 0 + is UnarySyntax -> 2 + + is BinarySyntax -> when (it.operation) { + PowerOperations.POW_OPERATION -> 1 + RingOperations.TIMES_OPERATION -> 3 + FieldOperations.DIV_OPERATION -> 3 + GroupOperations.MINUS_OPERATION -> 4 + GroupOperations.PLUS_OPERATION -> 4 + else -> 0 + } + + else -> 0 + } + } + } +} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt deleted file mode 100644 index 3400db0f8..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.MstField -import space.kscience.kmath.expressions.MstRing -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.interpret -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.invoke -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class TestCompilerConsistencyWithInterpreter { - @Test - fun intRing() = runCompilerTest { - val mst = MstRing { - binaryOperationFunction("+")( - unaryOperationFunction("+")( - (x - (2.toByte() + (scale( - add(number(1), number(1)), - 2.0, - ) + 1.toByte()))) * 3.0 - 1.toByte() - ), - - number(1), - ) * number(2) - } - - assertEquals( - mst.interpret(IntRing, x to 3), - mst.compile(IntRing, x to 3), - ) - } - - @Test - fun doubleField() = runCompilerTest { - val mst = MstField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( - (3.0 - (x + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 - + number(1), - number(1) / 2 + number(2.0) * one, - ) + zero - } - - assertEquals( - mst.interpret(DoubleField, x to 2.0), - mst.compile(DoubleField, x to 2.0), - ) - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt deleted file mode 100644 index bf56b80a6..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.MstExtendedField -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class TestCompilerOperations { - @Test - fun testUnaryPlus() = runCompilerTest { - val expr = MstExtendedField { +x }.compileToExpression(DoubleField) - assertEquals(2.0, expr(x to 2.0)) - } - - @Test - fun testUnaryMinus() = runCompilerTest { - val expr = MstExtendedField { -x }.compileToExpression(DoubleField) - assertEquals(-2.0, expr(x to 2.0)) - } - - @Test - fun testAdd() = runCompilerTest { - val expr = MstExtendedField { x + x }.compileToExpression(DoubleField) - assertEquals(4.0, expr(x to 2.0)) - } - - @Test - fun testSine() = runCompilerTest { - val expr = MstExtendedField { sin(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 0.0)) - } - - @Test - fun testCosine() = runCompilerTest { - val expr = MstExtendedField { cos(x) }.compileToExpression(DoubleField) - assertEquals(1.0, expr(x to 0.0)) - } - - @Test - fun testTangent() = runCompilerTest { - val expr = MstExtendedField { tan(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 0.0)) - } - - @Test - fun testArcSine() = runCompilerTest { - val expr = MstExtendedField { asin(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 0.0)) - } - - @Test - fun testArcCosine() = runCompilerTest { - val expr = MstExtendedField { acos(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 1.0)) - } - - @Test - fun testAreaHyperbolicSine() = runCompilerTest { - val expr = MstExtendedField { asinh(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 0.0)) - } - - @Test - fun testSubtract() = runCompilerTest { - val expr = MstExtendedField { x - x }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 2.0)) - } - - @Test - fun testDivide() = runCompilerTest { - val expr = MstExtendedField { x / x }.compileToExpression(DoubleField) - assertEquals(1.0, expr(x to 2.0)) - } - - @Test - fun testPower() = runCompilerTest { - val expr = MstExtendedField { x pow 2 }.compileToExpression(DoubleField) - assertEquals(4.0, expr(x to 2.0)) - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt deleted file mode 100644 index f23d36240..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.MstRing -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.Symbol.Companion.y -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.invoke -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - -internal class TestCompilerVariables { - @Test - fun testNoVariables() = runCompilerTest { - val expr = "0".parseMath().compileToExpression(DoubleField) - assertEquals(0.0, expr(), 0.0001) - } - - @Test - fun testOneVariable() = runCompilerTest { - val expr = MstRing { x }.compileToExpression(IntRing) - assertEquals(1, expr(x to 1)) - } - - @Test - fun testTwoVariables() = runCompilerTest { - val expr = "y+x/y+x".parseMath().compileToExpression(DoubleField) - assertEquals(8.0, expr(x to 4.0, y to 2.0)) - } - - @Test - fun testUndefinedVariableFails() = runCompilerTest { - val expr = MstRing { x }.compileToExpression(IntRing) - assertFailsWith { expr() } - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt deleted file mode 100644 index 95b804455..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.operations.ByteRing -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.pi -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.fail - -internal class TestFolding { - @Test - fun foldUnary() = assertEquals( - -1, - ("-(1)".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldDeepUnary() = assertEquals( - 1, - ("-(-(1))".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldBinary() = assertEquals( - 2, - ("1*2".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldDeepBinary() = assertEquals( - 10, - ("1*2*5".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldSymbol() = assertEquals( - DoubleField.pi, - ("pi".parseMath().evaluateConstants(DoubleField) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldNumeric() = assertEquals( - 42.toByte(), - ("42".parseMath().evaluateConstants(ByteRing) as? TypedMst.Constant ?: fail()).value, - ) -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt deleted file mode 100644 index 4b3631663..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.interpret -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class TestParserPrecedence { - @Test - fun test1(): Unit = assertEquals(6.0, "2*2+2".parseMath().interpret(f)) - - @Test - fun test2(): Unit = assertEquals(6.0, "2+2*2".parseMath().interpret(f)) - - @Test - fun test3(): Unit = assertEquals(10.0, "2^3+2".parseMath().interpret(f)) - - @Test - fun test4(): Unit = assertEquals(10.0, "2+2^3".parseMath().interpret(f)) - - @Test - fun test5(): Unit = assertEquals(16.0, "2^3*2".parseMath().interpret(f)) - - @Test - fun test6(): Unit = assertEquals(16.0, "2*2^3".parseMath().interpret(f)) - - @Test - fun test7(): Unit = assertEquals(18.0, "2+2^3*2".parseMath().interpret(f)) - - @Test - fun test8(): Unit = assertEquals(18.0, "2*2^3+2".parseMath().interpret(f)) - - private companion object { - private val f = DoubleField - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt deleted file mode 100644 index fe035c69f..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing - -internal interface CompilerTestContext { - fun MST.compileToExpression(algebra: IntRing): Expression - fun MST.compile(algebra: IntRing, arguments: Map): Int - fun MST.compile(algebra: IntRing, vararg arguments: Pair): Int = compile(algebra, mapOf(*arguments)) - fun MST.compileToExpression(algebra: DoubleField): Expression - fun MST.compile(algebra: DoubleField, arguments: Map): Double - - fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = - compile(algebra, mapOf(*arguments)) -} - -internal expect inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) diff --git a/kmath-ast/src/commonTest/kotlin/space/kscisnce/kmath/ast/InterpretTest.kt b/kmath-ast/src/commonTest/kotlin/space/kscisnce/kmath/ast/InterpretTest.kt new file mode 100644 index 000000000..93fde5aab --- /dev/null +++ b/kmath-ast/src/commonTest/kotlin/space/kscisnce/kmath/ast/InterpretTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscisnce.kmath.ast + +import space.kscience.kmath.expressions.MstField +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.expressions.toExpression +import space.kscience.kmath.misc.Symbol.Companion.x +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.bindSymbol +import space.kscience.kmath.operations.invoke +import kotlin.test.Test + +class InterpretTest { + + @Test + fun interpretation(){ + val expr = MstField { + val x = bindSymbol(x) + x * 2.0 + number(2.0) / x - 16.0 + }.toExpression(DoubleField) + expr(x to 2.2) + } +} \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt deleted file mode 100644 index f6411334c..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast.rendering - -internal actual fun Double.multiplatformToString(): String { - val d = this - if (d >= 1e7 || d <= -1e7) return js("d.toExponential()") as String - return toString() -} - -internal actual fun Float.multiplatformToString(): String { - val d = this - if (d >= 1e7f || d <= -1e7f) return js("d.toExponential()") as String - return toString() -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt index 87c2df2d2..83914f3ec 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt @@ -1,52 +1,87 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.estree -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.ast.evaluateConstants import space.kscience.kmath.estree.internal.ESTreeBuilder +import space.kscience.kmath.estree.internal.estree.BaseExpression import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.MST.* import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.internal.estree.BaseExpression +import space.kscience.kmath.misc.Symbol import space.kscience.kmath.operations.Algebra +import space.kscience.kmath.operations.NumericAlgebra + +@PublishedApi +internal fun MST.compileWith(algebra: Algebra): Expression { + fun ESTreeBuilder.visit(node: MST): BaseExpression = when (node) { + is Symbolic -> { + val symbol = algebra.bindSymbolOrNull(node.value) + + if (symbol != null) + constant(symbol) + else + variable(node.value) + } + + is Numeric -> constant(node.value) + + is Unary -> when { + algebra is NumericAlgebra && node.value is Numeric -> constant( + algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) + + else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) + } + + is Binary -> when { + algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant( + algebra.binaryOperationFunction(node.operation).invoke( + algebra.number((node.left as Numeric).value), + algebra.number((node.right as Numeric).value) + ) + ) + + algebra is NumericAlgebra && node.left is Numeric -> call( + algebra.leftSideNumberOperationFunction(node.operation), + visit(node.left), + visit(node.right), + ) + + algebra is NumericAlgebra && node.right is Numeric -> call( + algebra.rightSideNumberOperationFunction(node.operation), + visit(node.left), + visit(node.right), + ) + + else -> call( + algebra.binaryOperationFunction(node.operation), + visit(node.left), + visit(node.right), + ) + } + } + + return ESTreeBuilder { visit(this@compileWith) }.instance +} /** * Create a compiled expression with given [MST] and given [algebra]. */ -@OptIn(UnstableKMathAPI::class) -public fun MST.compileToExpression(algebra: Algebra): Expression { - val typed = evaluateConstants(algebra) - if (typed is TypedMst.Constant) return Expression { typed.value } +public fun MST.compileToExpression(algebra: Algebra): Expression = compileWith(algebra) - fun ESTreeBuilder.visit(node: TypedMst): BaseExpression = when (node) { - is TypedMst.Constant -> constant(node.value) - is TypedMst.Variable -> variable(node.symbol) - is TypedMst.Unary -> call(node.function, visit(node.value)) - - is TypedMst.Binary -> call( - node.function, - visit(node.left), - visit(node.right), - ) - } - - return ESTreeBuilder { visit(typed) }.instance -} /** * Compile given MST to expression and evaluate it against [arguments] */ -public fun MST.compile(algebra: Algebra, arguments: Map): T = - compileToExpression(algebra)(arguments) +public inline fun MST.compile(algebra: Algebra, arguments: Map): T = + compileToExpression(algebra).invoke(arguments) + /** * Compile given MST to expression and evaluate it against [arguments] */ -public fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = - compileToExpression(algebra)(*arguments) +public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = + compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt index 1517cdef2..6f917a24c 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -1,14 +1,14 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.estree.internal +import space.kscience.kmath.estree.internal.astring.generate +import space.kscience.kmath.estree.internal.estree.* import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.internal.astring.generate -import space.kscience.kmath.internal.estree.* +import space.kscience.kmath.misc.Symbol internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExpression) { private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression { @@ -22,20 +22,28 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp } } - @Suppress("UNUSED_VARIABLE") val instance: Expression by lazy { val node = Program( sourceType = "script", - ReturnStatement(bodyCallback()) + VariableDeclaration( + kind = "var", + VariableDeclarator( + id = Identifier("executable"), + init = FunctionExpression( + params = arrayOf(Identifier("constants"), Identifier("arguments")), + body = BlockStatement(ReturnStatement(bodyCallback())), + ), + ), + ), ) - val code = generate(node) - GeneratedExpression(js("new Function('constants', 'arguments_0', code)"), constants.toTypedArray()) + eval(generate(node)) + GeneratedExpression(js("executable"), constants.toTypedArray()) } private val constants = mutableListOf() - fun constant(value: Any?): BaseExpression = when { + fun constant(value: Any?) = when { value == null || jsTypeOf(value) == "number" || jsTypeOf(value) == "string" || jsTypeOf(value) == "boolean" -> SimpleLiteral(value) @@ -53,8 +61,7 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp } } - fun variable(name: Symbol): BaseExpression = - call(getOrFail, Identifier("arguments_0"), SimpleLiteral(name.identity)) + fun variable(name: String): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name)) fun call(function: Function, vararg args: BaseExpression): BaseExpression = SimpleCallExpression( optional = false, diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.kt similarity index 86% rename from kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt rename to kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.kt index cc4360f8d..354757b83 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.kt @@ -1,14 +1,14 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:JsModule("astring") @file:JsNonModule -package space.kscience.kmath.internal.astring +package space.kscience.kmath.estree.internal.astring -import space.kscience.kmath.internal.estree.BaseNode +import space.kscience.kmath.estree.internal.estree.BaseNode internal external interface Options { var indent: String? diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt index 2434788ec..eb5c1e3dd 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/emitter/emitter.kt similarity index 84% rename from kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt rename to kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/emitter/emitter.kt index a2a04da79..7707f53a2 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/emitter/emitter.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.internal.emitter +package space.kscience.kmath.estree.internal.emitter internal open external class Emitter { constructor(obj: Any) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/estree/estree.extensions.kt similarity index 88% rename from kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt rename to kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/estree/estree.extensions.kt index 2dd2c08cd..9ba11e085 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/estree/estree.extensions.kt @@ -1,11 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("unused") - -package space.kscience.kmath.internal.estree +package space.kscience.kmath.estree.internal.estree internal fun Program(sourceType: String, vararg body: dynamic) = object : Program { override var type = "Program" @@ -30,10 +28,9 @@ internal fun Identifier(name: String) = object : Identifier { override var name = name } -internal fun FunctionExpression(id: Identifier?, params: Array, body: BlockStatement) = object : FunctionExpression { +internal fun FunctionExpression(params: Array, body: BlockStatement) = object : FunctionExpression { override var params = params override var type = "FunctionExpression" - override var id: Identifier? = id override var body = body } diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/estree/estree.kt similarity index 99% rename from kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt rename to kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/estree/estree.kt index bf4a25367..a0e42db5d 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/estree/estree.kt @@ -1,11 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("ClassName") - -package space.kscience.kmath.internal.estree +package space.kscience.kmath.estree.internal.estree import kotlin.js.RegExp diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/stream/stream.kt similarity index 59% rename from kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt rename to kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/stream/stream.kt index ced165a3a..4bdeeea0b 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/stream/stream.kt @@ -1,11 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.internal.stream +package space.kscience.kmath.estree.internal.stream -import space.kscience.kmath.internal.emitter.Emitter +import space.kscience.kmath.estree.internal.emitter.Emitter internal open external class Stream : Emitter { open fun pipe(dest: Any, options: Any): Any diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt similarity index 89% rename from kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt rename to kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt index 2c0dc9de1..a3c721ed4 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.internal.tsstdlib +package space.kscience.kmath.estree.internal.tsstdlib internal external interface IteratorYieldResult { var done: Boolean? diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/tsstdlib/lib.es5.kt similarity index 86% rename from kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt rename to kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/tsstdlib/lib.es5.kt index f20e2d865..d2413b3e3 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/tsstdlib/lib.es5.kt @@ -1,11 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION") -package space.kscience.kmath.internal.tsstdlib +package space.kscience.kmath.estree.internal.tsstdlib import kotlin.js.RegExp @@ -38,8 +38,6 @@ internal external interface RegExpConstructor { var lastMatch: String } -internal typealias Record = Any - internal external interface ConcatArray { var length: Number @@ -87,10 +85,3 @@ internal external interface ArrayLike { } internal typealias Extract = Any - -internal external interface PromiseLike { - fun then( - onfulfilled: ((value: T) -> Any?)? = definedExternally, - onrejected: ((reason: Any) -> Any?)? = definedExternally - ): PromiseLike -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt deleted file mode 100644 index a17726c9d..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.internal.astring - -internal typealias Generator = Any diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt deleted file mode 100644 index 8ea699837..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", - "OVERRIDING_FINAL_MEMBER", - "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", - "ObjectPropertyName", - "ClassName", -) -@file:JsNonModule -@file:JsModule("js-base64") - -package space.kscience.kmath.internal.base64 - -import org.khronos.webgl.Uint8Array - -internal external var version: Any - -internal external var VERSION: Any - -internal external var btoaPolyfill: (bin: String) -> String - -internal external var _btoa: (bin: String) -> String - -internal external var fromUint8Array: (u8a: Uint8Array, urlsafe: Boolean) -> String - -internal external var utob: (u: String) -> String - -internal external var encode: (src: String, urlsafe: Boolean) -> String - -internal external var encodeURI: (src: String) -> String - -internal external var btou: (b: String) -> String - -internal external var atobPolyfill: (asc: String) -> String - -internal external var _atob: (asc: String) -> String - -internal external var toUint8Array: (a: String) -> Uint8Array - -internal external var decode: (src: String) -> String - -internal external var isValid: (src: Any) -> Boolean - -internal external var extendString: () -> Unit - -internal external var extendUint8Array: () -> Unit - -internal external var extendBuiltins: () -> Unit diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt deleted file mode 100644 index d907a12c9..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt +++ /dev/null @@ -1,2239 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", - "OVERRIDING_FINAL_MEMBER", - "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", - "PropertyName", - "ClassName", -) - -@file:JsModule("binaryen") -@file:JsNonModule - -package space.kscience.kmath.internal.binaryen - -import org.khronos.webgl.Uint8Array -import kotlin.js.Promise - -internal external var isReady: Boolean - -internal external var ready: Promise - -internal external var none: Type - -internal external var i32: Type - -internal external var i64: Type - -internal external var f32: Type - -internal external var f64: Type - -internal external var v128: Type - -internal external var funcref: Type - -internal external var anyref: Type - -internal external var nullref: Type - -internal external var exnref: Type - -internal external var unreachable: Type - -internal external var auto: Type - -internal external fun createType(types: Array): Type - -internal external fun expandType(type: Type): Array - -internal external enum class ExpressionIds { - Invalid, - Block, - If, - Loop, - Break, - Switch, - Call, - CallIndirect, - LocalGet, - LocalSet, - GlobalGet, - GlobalSet, - Load, - Store, - Const, - Unary, - Binary, - Select, - Drop, - Return, - Host, - Nop, - Unreachable, - AtomicCmpxchg, - AtomicRMW, - AtomicWait, - AtomicNotify, - AtomicFence, - SIMDExtract, - SIMDReplace, - SIMDShuffle, - SIMDTernary, - SIMDShift, - SIMDLoad, - MemoryInit, - DataDrop, - MemoryCopy, - MemoryFill, - RefNull, - RefIsNull, - RefFunc, - Try, - Throw, - Rethrow, - BrOnExn, - TupleMake, - TupleExtract, - Push, - Pop -} - -internal external var InvalidId: ExpressionIds - -internal external var BlockId: ExpressionIds - -internal external var IfId: ExpressionIds - -internal external var LoopId: ExpressionIds - -internal external var BreakId: ExpressionIds - -internal external var SwitchId: ExpressionIds - -internal external var CallId: ExpressionIds - -internal external var CallIndirectId: ExpressionIds - -internal external var LocalGetId: ExpressionIds - -internal external var LocalSetId: ExpressionIds - -internal external var GlobalGetId: ExpressionIds - -internal external var GlobalSetId: ExpressionIds - -internal external var LoadId: ExpressionIds - -internal external var StoreId: ExpressionIds - -internal external var ConstId: ExpressionIds - -internal external var UnaryId: ExpressionIds - -internal external var BinaryId: ExpressionIds - -internal external var SelectId: ExpressionIds - -internal external var DropId: ExpressionIds - -internal external var ReturnId: ExpressionIds - -internal external var HostId: ExpressionIds - -internal external var NopId: ExpressionIds - -internal external var UnreachableId: ExpressionIds - -internal external var AtomicCmpxchgId: ExpressionIds - -internal external var AtomicRMWId: ExpressionIds - -internal external var AtomicWaitId: ExpressionIds - -internal external var AtomicNotifyId: ExpressionIds - -internal external var AtomicFenceId: ExpressionIds - -internal external var SIMDExtractId: ExpressionIds - -internal external var SIMDReplaceId: ExpressionIds - -internal external var SIMDShuffleId: ExpressionIds - -internal external var SIMDTernaryId: ExpressionIds - -internal external var SIMDShiftId: ExpressionIds - -internal external var SIMDLoadId: ExpressionIds - -internal external var MemoryInitId: ExpressionIds - -internal external var DataDropId: ExpressionIds - -internal external var MemoryCopyId: ExpressionIds - -internal external var MemoryFillId: ExpressionIds - -internal external var RefNullId: ExpressionIds - -internal external var RefIsNullId: ExpressionIds - -internal external var RefFuncId: ExpressionIds - -internal external var TryId: ExpressionIds - -internal external var ThrowId: ExpressionIds - -internal external var RethrowId: ExpressionIds - -internal external var BrOnExnId: ExpressionIds - -internal external var TupleMakeId: ExpressionIds - -internal external var TupleExtractId: ExpressionIds - -internal external var PushId: ExpressionIds - -internal external var PopId: ExpressionIds - -internal external enum class ExternalKinds { - Function, - Table, - Memory, - Global, - Event -} - -internal external var ExternalFunction: ExternalKinds - -internal external var ExternalTable: ExternalKinds - -internal external var ExternalMemory: ExternalKinds - -internal external var ExternalGlobal: ExternalKinds - -internal external var ExternalEvent: ExternalKinds - -internal external enum class Features { - MVP, - Atomics, - MutableGlobals, - TruncSat, - SIMD, - BulkMemory, - SignExt, - ExceptionHandling, - TailCall, - ReferenceTypes, - Multivalue, - GC, - Memory64, - All -} - -internal external enum class Operations { - ClzInt32, - CtzInt32, - PopcntInt32, - NegFloat32, - AbsFloat32, - CeilFloat32, - FloorFloat32, - TruncFloat32, - NearestFloat32, - SqrtFloat32, - EqZInt32, - ClzInt64, - CtzInt64, - PopcntInt64, - NegFloat64, - AbsFloat64, - CeilFloat64, - FloorFloat64, - TruncFloat64, - NearestFloat64, - SqrtFloat64, - EqZInt64, - ExtendSInt32, - ExtendUInt32, - WrapInt64, - TruncSFloat32ToInt32, - TruncSFloat32ToInt64, - TruncUFloat32ToInt32, - TruncUFloat32ToInt64, - TruncSFloat64ToInt32, - TruncSFloat64ToInt64, - TruncUFloat64ToInt32, - TruncUFloat64ToInt64, - TruncSatSFloat32ToInt32, - TruncSatSFloat32ToInt64, - TruncSatUFloat32ToInt32, - TruncSatUFloat32ToInt64, - TruncSatSFloat64ToInt32, - TruncSatSFloat64ToInt64, - TruncSatUFloat64ToInt32, - TruncSatUFloat64ToInt64, - ReinterpretFloat32, - ReinterpretFloat64, - ConvertSInt32ToFloat32, - ConvertSInt32ToFloat64, - ConvertUInt32ToFloat32, - ConvertUInt32ToFloat64, - ConvertSInt64ToFloat32, - ConvertSInt64ToFloat64, - ConvertUInt64ToFloat32, - ConvertUInt64ToFloat64, - PromoteFloat32, - DemoteFloat64, - ReinterpretInt32, - ReinterpretInt64, - ExtendS8Int32, - ExtendS16Int32, - ExtendS8Int64, - ExtendS16Int64, - ExtendS32Int64, - AddInt32, - SubInt32, - MulInt32, - DivSInt32, - DivUInt32, - RemSInt32, - RemUInt32, - AndInt32, - OrInt32, - XorInt32, - ShlInt32, - ShrUInt32, - ShrSInt32, - RotLInt32, - RotRInt32, - EqInt32, - NeInt32, - LtSInt32, - LtUInt32, - LeSInt32, - LeUInt32, - GtSInt32, - GtUInt32, - GeSInt32, - GeUInt32, - AddInt64, - SubInt64, - MulInt64, - DivSInt64, - DivUInt64, - RemSInt64, - RemUInt64, - AndInt64, - OrInt64, - XorInt64, - ShlInt64, - ShrUInt64, - ShrSInt64, - RotLInt64, - RotRInt64, - EqInt64, - NeInt64, - LtSInt64, - LtUInt64, - LeSInt64, - LeUInt64, - GtSInt64, - GtUInt64, - GeSInt64, - GeUInt64, - AddFloat32, - SubFloat32, - MulFloat32, - DivFloat32, - CopySignFloat32, - MinFloat32, - MaxFloat32, - EqFloat32, - NeFloat32, - LtFloat32, - LeFloat32, - GtFloat32, - GeFloat32, - AddFloat64, - SubFloat64, - MulFloat64, - DivFloat64, - CopySignFloat64, - MinFloat64, - MaxFloat64, - EqFloat64, - NeFloat64, - LtFloat64, - LeFloat64, - GtFloat64, - GeFloat64, - MemorySize, - MemoryGrow, - AtomicRMWAdd, - AtomicRMWSub, - AtomicRMWAnd, - AtomicRMWOr, - AtomicRMWXor, - AtomicRMWXchg, - SplatVecI8x16, - ExtractLaneSVecI8x16, - ExtractLaneUVecI8x16, - ReplaceLaneVecI8x16, - SplatVecI16x8, - ExtractLaneSVecI16x8, - ExtractLaneUVecI16x8, - ReplaceLaneVecI16x8, - SplatVecI32x4, - ExtractLaneVecI32x4, - ReplaceLaneVecI32x4, - SplatVecI64x2, - ExtractLaneVecI64x2, - ReplaceLaneVecI64x2, - SplatVecF32x4, - ExtractLaneVecF32x4, - ReplaceLaneVecF32x4, - SplatVecF64x2, - ExtractLaneVecF64x2, - ReplaceLaneVecF64x2, - EqVecI8x16, - NeVecI8x16, - LtSVecI8x16, - LtUVecI8x16, - GtSVecI8x16, - GtUVecI8x16, - LeSVecI8x16, - LeUVecI8x16, - GeSVecI8x16, - GeUVecI8x16, - EqVecI16x8, - NeVecI16x8, - LtSVecI16x8, - LtUVecI16x8, - GtSVecI16x8, - GtUVecI16x8, - LeSVecI16x8, - LeUVecI16x8, - GeSVecI16x8, - GeUVecI16x8, - EqVecI32x4, - NeVecI32x4, - LtSVecI32x4, - LtUVecI32x4, - GtSVecI32x4, - GtUVecI32x4, - LeSVecI32x4, - LeUVecI32x4, - GeSVecI32x4, - GeUVecI32x4, - EqVecF32x4, - NeVecF32x4, - LtVecF32x4, - GtVecF32x4, - LeVecF32x4, - GeVecF32x4, - EqVecF64x2, - NeVecF64x2, - LtVecF64x2, - GtVecF64x2, - LeVecF64x2, - GeVecF64x2, - NotVec128, - AndVec128, - OrVec128, - XorVec128, - AndNotVec128, - BitselectVec128, - NegVecI8x16, - AnyTrueVecI8x16, - AllTrueVecI8x16, - ShlVecI8x16, - ShrSVecI8x16, - ShrUVecI8x16, - AddVecI8x16, - AddSatSVecI8x16, - AddSatUVecI8x16, - SubVecI8x16, - SubSatSVecI8x16, - SubSatUVecI8x16, - MulVecI8x16, - MinSVecI8x16, - MinUVecI8x16, - MaxSVecI8x16, - MaxUVecI8x16, - NegVecI16x8, - AnyTrueVecI16x8, - AllTrueVecI16x8, - ShlVecI16x8, - ShrSVecI16x8, - ShrUVecI16x8, - AddVecI16x8, - AddSatSVecI16x8, - AddSatUVecI16x8, - SubVecI16x8, - SubSatSVecI16x8, - SubSatUVecI16x8, - MulVecI16x8, - MinSVecI16x8, - MinUVecI16x8, - MaxSVecI16x8, - MaxUVecI16x8, - DotSVecI16x8ToVecI32x4, - NegVecI32x4, - AnyTrueVecI32x4, - AllTrueVecI32x4, - ShlVecI32x4, - ShrSVecI32x4, - ShrUVecI32x4, - AddVecI32x4, - SubVecI32x4, - MulVecI32x4, - MinSVecI32x4, - MinUVecI32x4, - MaxSVecI32x4, - MaxUVecI32x4, - NegVecI64x2, - AnyTrueVecI64x2, - AllTrueVecI64x2, - ShlVecI64x2, - ShrSVecI64x2, - ShrUVecI64x2, - AddVecI64x2, - SubVecI64x2, - AbsVecF32x4, - NegVecF32x4, - SqrtVecF32x4, - QFMAVecF32x4, - QFMSVecF32x4, - AddVecF32x4, - SubVecF32x4, - MulVecF32x4, - DivVecF32x4, - MinVecF32x4, - MaxVecF32x4, - AbsVecF64x2, - NegVecF64x2, - SqrtVecF64x2, - QFMAVecF64x2, - QFMSVecF64x2, - AddVecF64x2, - SubVecF64x2, - MulVecF64x2, - DivVecF64x2, - MinVecF64x2, - MaxVecF64x2, - TruncSatSVecF32x4ToVecI32x4, - TruncSatUVecF32x4ToVecI32x4, - TruncSatSVecF64x2ToVecI64x2, - TruncSatUVecF64x2ToVecI64x2, - ConvertSVecI32x4ToVecF32x4, - ConvertUVecI32x4ToVecF32x4, - ConvertSVecI64x2ToVecF64x2, - ConvertUVecI64x2ToVecF64x2, - LoadSplatVec8x16, - LoadSplatVec16x8, - LoadSplatVec32x4, - LoadSplatVec64x2, - LoadExtSVec8x8ToVecI16x8, - LoadExtUVec8x8ToVecI16x8, - LoadExtSVec16x4ToVecI32x4, - LoadExtUVec16x4ToVecI32x4, - LoadExtSVec32x2ToVecI64x2, - LoadExtUVec32x2ToVecI64x2, - NarrowSVecI16x8ToVecI8x16, - NarrowUVecI16x8ToVecI8x16, - NarrowSVecI32x4ToVecI16x8, - NarrowUVecI32x4ToVecI16x8, - WidenLowSVecI8x16ToVecI16x8, - WidenHighSVecI8x16ToVecI16x8, - WidenLowUVecI8x16ToVecI16x8, - WidenHighUVecI8x16ToVecI16x8, - WidenLowSVecI16x8ToVecI32x4, - WidenHighSVecI16x8ToVecI32x4, - WidenLowUVecI16x8ToVecI32x4, - WidenHighUVecI16x8ToVecI32x4, - SwizzleVec8x16 -} - -internal external var ClzInt32: Operations - -internal external var CtzInt32: Operations - -internal external var PopcntInt32: Operations - -internal external var NegFloat32: Operations - -internal external var AbsFloat32: Operations - -internal external var CeilFloat32: Operations - -internal external var FloorFloat32: Operations - -internal external var TruncFloat32: Operations - -internal external var NearestFloat32: Operations - -internal external var SqrtFloat32: Operations - -internal external var EqZInt32: Operations - -internal external var ClzInt64: Operations - -internal external var CtzInt64: Operations - -internal external var PopcntInt64: Operations - -internal external var NegFloat64: Operations - -internal external var AbsFloat64: Operations - -internal external var CeilFloat64: Operations - -internal external var FloorFloat64: Operations - -internal external var TruncFloat64: Operations - -internal external var NearestFloat64: Operations - -internal external var SqrtFloat64: Operations - -internal external var EqZInt64: Operations - -internal external var ExtendSInt32: Operations - -internal external var ExtendUInt32: Operations - -internal external var WrapInt64: Operations - -internal external var TruncSFloat32ToInt32: Operations - -internal external var TruncSFloat32ToInt64: Operations - -internal external var TruncUFloat32ToInt32: Operations - -internal external var TruncUFloat32ToInt64: Operations - -internal external var TruncSFloat64ToInt32: Operations - -internal external var TruncSFloat64ToInt64: Operations - -internal external var TruncUFloat64ToInt32: Operations - -internal external var TruncUFloat64ToInt64: Operations - -internal external var TruncSatSFloat32ToInt32: Operations - -internal external var TruncSatSFloat32ToInt64: Operations - -internal external var TruncSatUFloat32ToInt32: Operations - -internal external var TruncSatUFloat32ToInt64: Operations - -internal external var TruncSatSFloat64ToInt32: Operations - -internal external var TruncSatSFloat64ToInt64: Operations - -internal external var TruncSatUFloat64ToInt32: Operations - -internal external var TruncSatUFloat64ToInt64: Operations - -internal external var ReinterpretFloat32: Operations - -internal external var ReinterpretFloat64: Operations - -internal external var ConvertSInt32ToFloat32: Operations - -internal external var ConvertSInt32ToFloat64: Operations - -internal external var ConvertUInt32ToFloat32: Operations - -internal external var ConvertUInt32ToFloat64: Operations - -internal external var ConvertSInt64ToFloat32: Operations - -internal external var ConvertSInt64ToFloat64: Operations - -internal external var ConvertUInt64ToFloat32: Operations - -internal external var ConvertUInt64ToFloat64: Operations - -internal external var PromoteFloat32: Operations - -internal external var DemoteFloat64: Operations - -internal external var ReinterpretInt32: Operations - -internal external var ReinterpretInt64: Operations - -internal external var ExtendS8Int32: Operations - -internal external var ExtendS16Int32: Operations - -internal external var ExtendS8Int64: Operations - -internal external var ExtendS16Int64: Operations - -internal external var ExtendS32Int64: Operations - -internal external var AddInt32: Operations - -internal external var SubInt32: Operations - -internal external var MulInt32: Operations - -internal external var DivSInt32: Operations - -internal external var DivUInt32: Operations - -internal external var RemSInt32: Operations - -internal external var RemUInt32: Operations - -internal external var AndInt32: Operations - -internal external var OrInt32: Operations - -internal external var XorInt32: Operations - -internal external var ShlInt32: Operations - -internal external var ShrUInt32: Operations - -internal external var ShrSInt32: Operations - -internal external var RotLInt32: Operations - -internal external var RotRInt32: Operations - -internal external var EqInt32: Operations - -internal external var NeInt32: Operations - -internal external var LtSInt32: Operations - -internal external var LtUInt32: Operations - -internal external var LeSInt32: Operations - -internal external var LeUInt32: Operations - -internal external var GtSInt32: Operations - -internal external var GtUInt32: Operations - -internal external var GeSInt32: Operations - -internal external var GeUInt32: Operations - -internal external var AddInt64: Operations - -internal external var SubInt64: Operations - -internal external var MulInt64: Operations - -internal external var DivSInt64: Operations - -internal external var DivUInt64: Operations - -internal external var RemSInt64: Operations - -internal external var RemUInt64: Operations - -internal external var AndInt64: Operations - -internal external var OrInt64: Operations - -internal external var XorInt64: Operations - -internal external var ShlInt64: Operations - -internal external var ShrUInt64: Operations - -internal external var ShrSInt64: Operations - -internal external var RotLInt64: Operations - -internal external var RotRInt64: Operations - -internal external var EqInt64: Operations - -internal external var NeInt64: Operations - -internal external var LtSInt64: Operations - -internal external var LtUInt64: Operations - -internal external var LeSInt64: Operations - -internal external var LeUInt64: Operations - -internal external var GtSInt64: Operations - -internal external var GtUInt64: Operations - -internal external var GeSInt64: Operations - -internal external var GeUInt64: Operations - -internal external var AddFloat32: Operations - -internal external var SubFloat32: Operations - -internal external var MulFloat32: Operations - -internal external var DivFloat32: Operations - -internal external var CopySignFloat32: Operations - -internal external var MinFloat32: Operations - -internal external var MaxFloat32: Operations - -internal external var EqFloat32: Operations - -internal external var NeFloat32: Operations - -internal external var LtFloat32: Operations - -internal external var LeFloat32: Operations - -internal external var GtFloat32: Operations - -internal external var GeFloat32: Operations - -internal external var AddFloat64: Operations - -internal external var SubFloat64: Operations - -internal external var MulFloat64: Operations - -internal external var DivFloat64: Operations - -internal external var CopySignFloat64: Operations - -internal external var MinFloat64: Operations - -internal external var MaxFloat64: Operations - -internal external var EqFloat64: Operations - -internal external var NeFloat64: Operations - -internal external var LtFloat64: Operations - -internal external var LeFloat64: Operations - -internal external var GtFloat64: Operations - -internal external var GeFloat64: Operations - -internal external var MemorySize: Operations - -internal external var MemoryGrow: Operations - -internal external var AtomicRMWAdd: Operations - -internal external var AtomicRMWSub: Operations - -internal external var AtomicRMWAnd: Operations - -internal external var AtomicRMWOr: Operations - -internal external var AtomicRMWXor: Operations - -internal external var AtomicRMWXchg: Operations - -internal external var SplatVecI8x16: Operations - -internal external var ExtractLaneSVecI8x16: Operations - -internal external var ExtractLaneUVecI8x16: Operations - -internal external var ReplaceLaneVecI8x16: Operations - -internal external var SplatVecI16x8: Operations - -internal external var ExtractLaneSVecI16x8: Operations - -internal external var ExtractLaneUVecI16x8: Operations - -internal external var ReplaceLaneVecI16x8: Operations - -internal external var SplatVecI32x4: Operations - -internal external var ExtractLaneVecI32x4: Operations - -internal external var ReplaceLaneVecI32x4: Operations - -internal external var SplatVecI64x2: Operations - -internal external var ExtractLaneVecI64x2: Operations - -internal external var ReplaceLaneVecI64x2: Operations - -internal external var SplatVecF32x4: Operations - -internal external var ExtractLaneVecF32x4: Operations - -internal external var ReplaceLaneVecF32x4: Operations - -internal external var SplatVecF64x2: Operations - -internal external var ExtractLaneVecF64x2: Operations - -internal external var ReplaceLaneVecF64x2: Operations - -internal external var EqVecI8x16: Operations - -internal external var NeVecI8x16: Operations - -internal external var LtSVecI8x16: Operations - -internal external var LtUVecI8x16: Operations - -internal external var GtSVecI8x16: Operations - -internal external var GtUVecI8x16: Operations - -internal external var LeSVecI8x16: Operations - -internal external var LeUVecI8x16: Operations - -internal external var GeSVecI8x16: Operations - -internal external var GeUVecI8x16: Operations - -internal external var EqVecI16x8: Operations - -internal external var NeVecI16x8: Operations - -internal external var LtSVecI16x8: Operations - -internal external var LtUVecI16x8: Operations - -internal external var GtSVecI16x8: Operations - -internal external var GtUVecI16x8: Operations - -internal external var LeSVecI16x8: Operations - -internal external var LeUVecI16x8: Operations - -internal external var GeSVecI16x8: Operations - -internal external var GeUVecI16x8: Operations - -internal external var EqVecI32x4: Operations - -internal external var NeVecI32x4: Operations - -internal external var LtSVecI32x4: Operations - -internal external var LtUVecI32x4: Operations - -internal external var GtSVecI32x4: Operations - -internal external var GtUVecI32x4: Operations - -internal external var LeSVecI32x4: Operations - -internal external var LeUVecI32x4: Operations - -internal external var GeSVecI32x4: Operations - -internal external var GeUVecI32x4: Operations - -internal external var EqVecF32x4: Operations - -internal external var NeVecF32x4: Operations - -internal external var LtVecF32x4: Operations - -internal external var GtVecF32x4: Operations - -internal external var LeVecF32x4: Operations - -internal external var GeVecF32x4: Operations - -internal external var EqVecF64x2: Operations - -internal external var NeVecF64x2: Operations - -internal external var LtVecF64x2: Operations - -internal external var GtVecF64x2: Operations - -internal external var LeVecF64x2: Operations - -internal external var GeVecF64x2: Operations - -internal external var NotVec128: Operations - -internal external var AndVec128: Operations - -internal external var OrVec128: Operations - -internal external var XorVec128: Operations - -internal external var AndNotVec128: Operations - -internal external var BitselectVec128: Operations - -internal external var NegVecI8x16: Operations - -internal external var AnyTrueVecI8x16: Operations - -internal external var AllTrueVecI8x16: Operations - -internal external var ShlVecI8x16: Operations - -internal external var ShrSVecI8x16: Operations - -internal external var ShrUVecI8x16: Operations - -internal external var AddVecI8x16: Operations - -internal external var AddSatSVecI8x16: Operations - -internal external var AddSatUVecI8x16: Operations - -internal external var SubVecI8x16: Operations - -internal external var SubSatSVecI8x16: Operations - -internal external var SubSatUVecI8x16: Operations - -internal external var MulVecI8x16: Operations - -internal external var MinSVecI8x16: Operations - -internal external var MinUVecI8x16: Operations - -internal external var MaxSVecI8x16: Operations - -internal external var MaxUVecI8x16: Operations - -internal external var NegVecI16x8: Operations - -internal external var AnyTrueVecI16x8: Operations - -internal external var AllTrueVecI16x8: Operations - -internal external var ShlVecI16x8: Operations - -internal external var ShrSVecI16x8: Operations - -internal external var ShrUVecI16x8: Operations - -internal external var AddVecI16x8: Operations - -internal external var AddSatSVecI16x8: Operations - -internal external var AddSatUVecI16x8: Operations - -internal external var SubVecI16x8: Operations - -internal external var SubSatSVecI16x8: Operations - -internal external var SubSatUVecI16x8: Operations - -internal external var MulVecI16x8: Operations - -internal external var MinSVecI16x8: Operations - -internal external var MinUVecI16x8: Operations - -internal external var MaxSVecI16x8: Operations - -internal external var MaxUVecI16x8: Operations - -internal external var DotSVecI16x8ToVecI32x4: Operations - -internal external var NegVecI32x4: Operations - -internal external var AnyTrueVecI32x4: Operations - -internal external var AllTrueVecI32x4: Operations - -internal external var ShlVecI32x4: Operations - -internal external var ShrSVecI32x4: Operations - -internal external var ShrUVecI32x4: Operations - -internal external var AddVecI32x4: Operations - -internal external var SubVecI32x4: Operations - -internal external var MulVecI32x4: Operations - -internal external var MinSVecI32x4: Operations - -internal external var MinUVecI32x4: Operations - -internal external var MaxSVecI32x4: Operations - -internal external var MaxUVecI32x4: Operations - -internal external var NegVecI64x2: Operations - -internal external var AnyTrueVecI64x2: Operations - -internal external var AllTrueVecI64x2: Operations - -internal external var ShlVecI64x2: Operations - -internal external var ShrSVecI64x2: Operations - -internal external var ShrUVecI64x2: Operations - -internal external var AddVecI64x2: Operations - -internal external var SubVecI64x2: Operations - -internal external var AbsVecF32x4: Operations - -internal external var NegVecF32x4: Operations - -internal external var SqrtVecF32x4: Operations - -internal external var QFMAVecF32x4: Operations - -internal external var QFMSVecF32x4: Operations - -internal external var AddVecF32x4: Operations - -internal external var SubVecF32x4: Operations - -internal external var MulVecF32x4: Operations - -internal external var DivVecF32x4: Operations - -internal external var MinVecF32x4: Operations - -internal external var MaxVecF32x4: Operations - -internal external var AbsVecF64x2: Operations - -internal external var NegVecF64x2: Operations - -internal external var SqrtVecF64x2: Operations - -internal external var QFMAVecF64x2: Operations - -internal external var QFMSVecF64x2: Operations - -internal external var AddVecF64x2: Operations - -internal external var SubVecF64x2: Operations - -internal external var MulVecF64x2: Operations - -internal external var DivVecF64x2: Operations - -internal external var MinVecF64x2: Operations - -internal external var MaxVecF64x2: Operations - -internal external var TruncSatSVecF32x4ToVecI32x4: Operations - -internal external var TruncSatUVecF32x4ToVecI32x4: Operations - -internal external var TruncSatSVecF64x2ToVecI64x2: Operations - -internal external var TruncSatUVecF64x2ToVecI64x2: Operations - -internal external var ConvertSVecI32x4ToVecF32x4: Operations - -internal external var ConvertUVecI32x4ToVecF32x4: Operations - -internal external var ConvertSVecI64x2ToVecF64x2: Operations - -internal external var ConvertUVecI64x2ToVecF64x2: Operations - -internal external var LoadSplatVec8x16: Operations - -internal external var LoadSplatVec16x8: Operations - -internal external var LoadSplatVec32x4: Operations - -internal external var LoadSplatVec64x2: Operations - -internal external var LoadExtSVec8x8ToVecI16x8: Operations - -internal external var LoadExtUVec8x8ToVecI16x8: Operations - -internal external var LoadExtSVec16x4ToVecI32x4: Operations - -internal external var LoadExtUVec16x4ToVecI32x4: Operations - -internal external var LoadExtSVec32x2ToVecI64x2: Operations - -internal external var LoadExtUVec32x2ToVecI64x2: Operations - -internal external var NarrowSVecI16x8ToVecI8x16: Operations - -internal external var NarrowUVecI16x8ToVecI8x16: Operations - -internal external var NarrowSVecI32x4ToVecI16x8: Operations - -internal external var NarrowUVecI32x4ToVecI16x8: Operations - -internal external var WidenLowSVecI8x16ToVecI16x8: Operations - -internal external var WidenHighSVecI8x16ToVecI16x8: Operations - -internal external var WidenLowUVecI8x16ToVecI16x8: Operations - -internal external var WidenHighUVecI8x16ToVecI16x8: Operations - -internal external var WidenLowSVecI16x8ToVecI32x4: Operations - -internal external var WidenHighSVecI16x8ToVecI32x4: Operations - -internal external var WidenLowUVecI16x8ToVecI32x4: Operations - -internal external var WidenHighUVecI16x8ToVecI32x4: Operations - -internal external var SwizzleVec8x16: Operations - -internal external interface `T$2` { - fun get(index: Number, type: Type): ExpressionRef - fun set(index: Number, value: ExpressionRef): ExpressionRef - fun tee(index: Number, value: ExpressionRef, type: Type): ExpressionRef -} - -internal external interface `T$3` { - fun get(name: String, type: Type): ExpressionRef - fun set(name: String, value: ExpressionRef): ExpressionRef -} - -internal external interface `T$4` { - fun size(): ExpressionRef - fun grow(value: ExpressionRef): ExpressionRef - fun init(segment: Number, dest: ExpressionRef, offset: ExpressionRef, size: ExpressionRef): ExpressionRef - fun copy(dest: ExpressionRef, source: ExpressionRef, size: ExpressionRef): ExpressionRef - fun fill(dest: ExpressionRef, value: ExpressionRef, size: ExpressionRef): ExpressionRef -} - -internal external interface `T$5` { - fun drop(segment: Number): ExpressionRef -} - -internal external interface `T$6` { - fun f32(value: ExpressionRef): ExpressionRef - fun f64(value: ExpressionRef): ExpressionRef -} - -internal external interface `T$7` { - fun add(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun sub(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun and(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun or(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun xor(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun xchg(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun cmpxchg(offset: Number, ptr: ExpressionRef, expected: ExpressionRef, replacement: ExpressionRef): ExpressionRef -} - -internal external interface `T$8` { - fun load(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load8_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load16_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store8(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store16(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - var rmw: `T$7` - var rmw8_u: `T$7` - var rmw16_u: `T$7` - fun wait(ptr: ExpressionRef, expected: ExpressionRef, timeout: ExpressionRef): ExpressionRef -} - -internal external interface `T$9` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store8(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store16(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(value: Number): ExpressionRef - fun clz(value: ExpressionRef): ExpressionRef - fun ctz(value: ExpressionRef): ExpressionRef - fun popcnt(value: ExpressionRef): ExpressionRef - fun eqz(value: ExpressionRef): ExpressionRef - var trunc_s: `T$6` - var trunc_u: `T$6` - var trunc_s_sat: `T$6` - var trunc_u_sat: `T$6` - fun reinterpret(value: ExpressionRef): ExpressionRef - fun extend8_s(value: ExpressionRef): ExpressionRef - fun extend16_s(value: ExpressionRef): ExpressionRef - fun wrap(value: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rem_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rem_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun and(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun or(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun xor(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shl(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shr_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shr_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rotl(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rotr(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - var atomic: `T$8` - fun pop(): ExpressionRef -} - -internal external interface `T$10` { - fun load(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load8_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load16_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load32_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store8(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store16(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store32(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - var rmw: `T$7` - var rmw8_u: `T$7` - var rmw16_u: `T$7` - var rmw32_u: `T$7` - fun wait(ptr: ExpressionRef, expected: ExpressionRef, timeout: ExpressionRef): ExpressionRef -} - -internal external interface `T$11` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load32_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load32_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store8(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store16(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store32(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(low: Number, high: Number): ExpressionRef - fun clz(value: ExpressionRef): ExpressionRef - fun ctz(value: ExpressionRef): ExpressionRef - fun popcnt(value: ExpressionRef): ExpressionRef - fun eqz(value: ExpressionRef): ExpressionRef - var trunc_s: `T$6` - var trunc_u: `T$6` - var trunc_s_sat: `T$6` - var trunc_u_sat: `T$6` - fun reinterpret(value: ExpressionRef): ExpressionRef - fun extend8_s(value: ExpressionRef): ExpressionRef - fun extend16_s(value: ExpressionRef): ExpressionRef - fun extend32_s(value: ExpressionRef): ExpressionRef - fun extend_s(value: ExpressionRef): ExpressionRef - fun extend_u(value: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rem_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rem_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun and(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun or(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun xor(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shl(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shr_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shr_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rotl(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rotr(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - var atomic: `T$10` - fun pop(): ExpressionRef -} - -internal external interface `T$12` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(value: Number): ExpressionRef - fun const_bits(value: Number): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun abs(value: ExpressionRef): ExpressionRef - fun ceil(value: ExpressionRef): ExpressionRef - fun floor(value: ExpressionRef): ExpressionRef - fun trunc(value: ExpressionRef): ExpressionRef - fun nearest(value: ExpressionRef): ExpressionRef - fun sqrt(value: ExpressionRef): ExpressionRef - fun reinterpret(value: ExpressionRef): ExpressionRef - var convert_s: `T$6` - var convert_u: `T$6` - fun demote(value: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun copysign(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun pop(): ExpressionRef -} - -internal external interface `T$13` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(value: Number): ExpressionRef - fun const_bits(low: Number, high: Number): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun abs(value: ExpressionRef): ExpressionRef - fun ceil(value: ExpressionRef): ExpressionRef - fun floor(value: ExpressionRef): ExpressionRef - fun trunc(value: ExpressionRef): ExpressionRef - fun nearest(value: ExpressionRef): ExpressionRef - fun sqrt(value: ExpressionRef): ExpressionRef - fun reinterpret(value: ExpressionRef): ExpressionRef - var convert_s: `T$6` - var convert_u: `T$6` - fun promote(value: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun copysign(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun pop(): ExpressionRef -} - -internal external interface `T$14` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(value: Number): ExpressionRef - fun not(value: ExpressionRef): ExpressionRef - fun and(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun or(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun xor(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun andnot(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun bitselect(left: ExpressionRef, right: ExpressionRef, cond: ExpressionRef): ExpressionRef - fun pop(): ExpressionRef -} - -internal external interface `T$15` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane_s(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun extract_lane_u(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun any_true(value: ExpressionRef): ExpressionRef - fun all_true(value: ExpressionRef): ExpressionRef - fun shl(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_s(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_u(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun add_saturate_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun add_saturate_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub_saturate_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub_saturate_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun avgr_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun narrow_i16x8_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun narrow_i16x8_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef -} - -internal external interface `T$16` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane_s(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun extract_lane_u(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun any_true(value: ExpressionRef): ExpressionRef - fun all_true(value: ExpressionRef): ExpressionRef - fun shl(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_s(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_u(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun add_saturate_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun add_saturate_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub_saturate_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub_saturate_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun avgr_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun narrow_i32x4_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun narrow_i32x4_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun widen_low_i8x16_s(value: ExpressionRef): ExpressionRef - fun widen_high_i8x16_s(value: ExpressionRef): ExpressionRef - fun widen_low_i8x16_u(value: ExpressionRef): ExpressionRef - fun widen_high_i8x16_u(value: ExpressionRef): ExpressionRef - fun load8x8_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8x8_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$17` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun any_true(value: ExpressionRef): ExpressionRef - fun all_true(value: ExpressionRef): ExpressionRef - fun shl(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_s(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_u(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun trunc_sat_f32x4_s(value: ExpressionRef): ExpressionRef - fun trunc_sat_f32x4_u(value: ExpressionRef): ExpressionRef - fun widen_low_i16x8_s(value: ExpressionRef): ExpressionRef - fun widen_high_i16x8_s(value: ExpressionRef): ExpressionRef - fun widen_low_i16x8_u(value: ExpressionRef): ExpressionRef - fun widen_high_i16x8_u(value: ExpressionRef): ExpressionRef - fun load16x4_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16x4_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$18` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun any_true(value: ExpressionRef): ExpressionRef - fun all_true(value: ExpressionRef): ExpressionRef - fun shl(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_s(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_u(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun trunc_sat_f64x2_s(value: ExpressionRef): ExpressionRef - fun trunc_sat_f64x2_u(value: ExpressionRef): ExpressionRef - fun load32x2_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load32x2_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$19` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun abs(value: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun sqrt(value: ExpressionRef): ExpressionRef - fun qfma(a: ExpressionRef, b: ExpressionRef, c: ExpressionRef): ExpressionRef - fun qfms(a: ExpressionRef, b: ExpressionRef, c: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun convert_i32x4_s(value: ExpressionRef): ExpressionRef - fun convert_i32x4_u(value: ExpressionRef): ExpressionRef -} - -internal external interface `T$20` { - fun shuffle(left: ExpressionRef, right: ExpressionRef, mask: Array): ExpressionRef - fun swizzle(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun load_splat(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$21` { - fun load_splat(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$22` { - fun pop(): ExpressionRef -} - -internal external interface `T$23` { - fun `null`(): ExpressionRef - fun is_null(value: ExpressionRef): ExpressionRef - fun func(name: String): ExpressionRef -} - -internal external interface `T$24` { - fun notify(ptr: ExpressionRef, notifyCount: ExpressionRef): ExpressionRef - fun fence(): ExpressionRef -} - -internal external interface `T$25` { - fun make(elements: Array): ExpressionRef - fun extract(tuple: ExpressionRef, index: Number): ExpressionRef -} - -internal external interface `T$26` { - var imported: Boolean - var segments: Array -} - -internal external interface `T$27` { - var binary: Uint8Array - var sourceMap: String? -} - -internal open external class Module { - open var ptr: Number - open fun block(label: String, children: Array, resultType: Type = definedExternally): ExpressionRef - open fun `if`( - condition: ExpressionRef, - ifTrue: ExpressionRef, - ifFalse: ExpressionRef = definedExternally - ): ExpressionRef - - open fun loop(label: String, body: ExpressionRef): ExpressionRef - open fun br( - label: String, - condition: ExpressionRef = definedExternally, - value: ExpressionRef = definedExternally - ): ExpressionRef - - open fun br_if( - label: String, - condition: ExpressionRef = definedExternally, - value: ExpressionRef = definedExternally - ): ExpressionRef - - open fun switch( - labels: Array, - defaultLabel: String, - condition: ExpressionRef, - value: ExpressionRef = definedExternally - ): ExpressionRef - - open fun call(name: String, operands: Array, returnType: Type): ExpressionRef - open fun return_call(name: String, operands: Array, returnType: Type): ExpressionRef - open fun call_indirect( - target: ExpressionRef, - operands: Array, - params: Type, - results: Type - ): ExpressionRef - - open fun return_call_indirect( - target: ExpressionRef, - operands: Array, - params: Type, - results: Type - ): ExpressionRef - - open var local: `T$2` - open var global: `T$3` - open var memory: `T$4` - open var data: `T$5` - open var i32: `T$9` - open var i64: `T$11` - open var f32: `T$12` - open var f64: `T$13` - open var v128: `T$14` - open var i8x16: `T$15` - open var i16x8: `T$16` - open var i32x4: `T$17` - open var i64x2: `T$18` - open var f32x4: `T$19` - open var f64x2: `T$19` - open var v8x16: `T$20` - open var v16x8: `T$21` - open var v32x4: `T$21` - open var v64x2: `T$21` - open var funcref: `T$22` - open var anyref: `T$22` - open var nullref: `T$22` - open var exnref: `T$22` - open var ref: `T$23` - open var atomic: `T$24` - open var tuple: `T$25` - open fun `try`(body: ExpressionRef, catchBody: ExpressionRef): ExpressionRef - open fun `throw`(event: String, operands: Array): ExpressionRef - open fun rethrow(exnref: ExpressionRef): ExpressionRef - open fun br_on_exn(label: String, event: String, exnref: ExpressionRef): ExpressionRef - open fun push(value: ExpressionRef): ExpressionRef - open fun select( - condition: ExpressionRef, - ifTrue: ExpressionRef, - ifFalse: ExpressionRef, - type: Type = definedExternally - ): ExpressionRef - - open fun drop(value: ExpressionRef): ExpressionRef - open fun `return`(value: ExpressionRef = definedExternally): ExpressionRef - open fun host(op: Operations, name: String, operands: Array): ExpressionRef - open fun nop(): ExpressionRef - open fun unreachable(): ExpressionRef - open fun addFunction(name: String, params: Type, results: Type, vars: Array, body: ExpressionRef): FunctionRef - open fun getFunction(name: String): FunctionRef - open fun removeFunction(name: String) - open fun getNumFunctions(): Number - open fun getFunctionByIndex(index: Number): FunctionRef - open fun addGlobal(name: String, type: Type, mutable: Boolean, init: ExpressionRef): GlobalRef - open fun getGlobal(name: String): GlobalRef - open fun removeGlobal(name: String) - open fun addEvent(name: String, attribute: Number, params: Type, results: Type): EventRef - open fun getEvent(name: String): EventRef - open fun removeEvent(name: String) - open fun addFunctionImport( - internalName: String, - externalModuleName: String, - externalBaseName: String, - params: Type, - results: Type - ) - - open fun addTableImport(internalName: String, externalModuleName: String, externalBaseName: String) - open fun addMemoryImport(internalName: String, externalModuleName: String, externalBaseName: String) - open fun addGlobalImport( - internalName: String, - externalModuleName: String, - externalBaseName: String, - globalType: Type - ) - - open fun addEventImport( - internalName: String, - externalModuleName: String, - externalBaseName: String, - attribute: Number, - params: Type, - results: Type - ) - - open fun addFunctionExport(internalName: String, externalName: String): ExportRef - open fun addTableExport(internalName: String, externalName: String): ExportRef - open fun addMemoryExport(internalName: String, externalName: String): ExportRef - open fun addGlobalExport(internalName: String, externalName: String): ExportRef - open fun removeExport(externalName: String) - open fun getNumExports(): Number - open fun getExportByIndex(index: Number): ExportRef - open fun setFunctionTable( - initial: Number, - maximum: Number, - funcNames: Array, - offset: ExpressionRef = definedExternally - ) - - open fun getFunctionTable(): `T$26` - open fun setMemory( - initial: Number, - maximum: Number, - exportName: String? = definedExternally, - segments: Array? = definedExternally, - flags: Array? = definedExternally, - shared: Boolean = definedExternally - ) - - open fun getNumMemorySegments(): Number - open fun getMemorySegmentInfoByIndex(index: Number): MemorySegmentInfo - open fun setStart(start: FunctionRef) - open fun getFeatures(): Features - open fun setFeatures(features: Features) - open fun addCustomSection(name: String, contents: Uint8Array) - open fun emitText(): String - open fun emitStackIR(optimize: Boolean = definedExternally): String - open fun emitAsmjs(): String - open fun validate(): Number - open fun optimize() - open fun optimizeFunction(func: String) - open fun optimizeFunction(func: FunctionRef) - open fun runPasses(passes: Array) - open fun runPassesOnFunction(func: String, passes: Array) - open fun runPassesOnFunction(func: FunctionRef, passes: Array) - open fun autoDrop() - open fun dispose() - open fun emitBinary(): Uint8Array - open fun emitBinary(sourceMapUrl: String?): `T$27` - open fun interpret() - open fun addDebugInfoFileName(filename: String): Number - open fun getDebugInfoFileName(index: Number): String? - open fun setDebugLocation( - func: FunctionRef, - expr: ExpressionRef, - fileIndex: Number, - lineNumber: Number, - columnNumber: Number - ) - - open fun copyExpression(expr: ExpressionRef): ExpressionRef -} - -internal external interface MemorySegment { - var offset: ExpressionRef - var data: Uint8Array - var passive: Boolean? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface TableElement { - var offset: ExpressionRef - var names: Array -} - -internal external fun wrapModule(ptr: Number): Module - -internal external fun getExpressionId(expression: ExpressionRef): Number - -internal external fun getExpressionType(expression: ExpressionRef): Type - -internal external fun getExpressionInfo(expression: ExpressionRef): ExpressionInfo - -internal external interface MemorySegmentInfo { - var offset: ExpressionRef - var data: Uint8Array - var passive: Boolean -} - -internal external interface ExpressionInfo { - var id: ExpressionIds - var type: Type -} - -internal external interface BlockInfo : ExpressionInfo { - var name: String - var children: Array -} - -internal external interface IfInfo : ExpressionInfo { - var condition: ExpressionRef - var ifTrue: ExpressionRef - var ifFalse: ExpressionRef -} - -internal external interface LoopInfo : ExpressionInfo { - var name: String - var body: ExpressionRef -} - -internal external interface BreakInfo : ExpressionInfo { - var name: String - var condition: ExpressionRef - var value: ExpressionRef -} - -internal external interface SwitchInfo : ExpressionInfo { - var names: Array - var defaultName: String? - var condition: ExpressionRef - var value: ExpressionRef -} - -internal external interface CallInfo : ExpressionInfo { - var isReturn: Boolean - var target: String - var operands: Array -} - -internal external interface CallIndirectInfo : ExpressionInfo { - var isReturn: Boolean - var target: ExpressionRef - var operands: Array -} - -internal external interface LocalGetInfo : ExpressionInfo { - var index: Number -} - -internal external interface LocalSetInfo : ExpressionInfo { - var isTee: Boolean - var index: Number - var value: ExpressionRef -} - -internal external interface GlobalGetInfo : ExpressionInfo { - var name: String -} - -internal external interface GlobalSetInfo : ExpressionInfo { - var name: String - var value: ExpressionRef -} - -internal external interface LoadInfo : ExpressionInfo { - var isAtomic: Boolean - var isSigned: Boolean - var offset: Number - var bytes: Number - var align: Number - var ptr: ExpressionRef -} - -internal external interface StoreInfo : ExpressionInfo { - var isAtomic: Boolean - var offset: Number - var bytes: Number - var align: Number - var ptr: ExpressionRef - var value: ExpressionRef -} - -internal external interface `T$28` { - var low: Number - var high: Number -} - -internal external interface ConstInfo : ExpressionInfo { - var value: dynamic /* Number | `T$28` */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface UnaryInfo : ExpressionInfo { - var op: Operations - var value: ExpressionRef -} - -internal external interface BinaryInfo : ExpressionInfo { - var op: Operations - var left: ExpressionRef - var right: ExpressionRef -} - -internal external interface SelectInfo : ExpressionInfo { - var ifTrue: ExpressionRef - var ifFalse: ExpressionRef - var condition: ExpressionRef -} - -internal external interface DropInfo : ExpressionInfo { - var value: ExpressionRef -} - -internal external interface ReturnInfo : ExpressionInfo { - var value: ExpressionRef -} - -internal external interface NopInfo : ExpressionInfo - -internal external interface UnreachableInfo : ExpressionInfo - -internal external interface HostInfo : ExpressionInfo { - var op: Operations - var nameOperand: String? - var operands: Array -} - -internal external interface AtomicRMWInfo : ExpressionInfo { - var op: Operations - var bytes: Number - var offset: Number - var ptr: ExpressionRef - var value: ExpressionRef -} - -internal external interface AtomicCmpxchgInfo : ExpressionInfo { - var bytes: Number - var offset: Number - var ptr: ExpressionRef - var expected: ExpressionRef - var replacement: ExpressionRef -} - -internal external interface AtomicWaitInfo : ExpressionInfo { - var ptr: ExpressionRef - var expected: ExpressionRef - var timeout: ExpressionRef - var expectedType: Type -} - -internal external interface AtomicNotifyInfo : ExpressionInfo { - var ptr: ExpressionRef - var notifyCount: ExpressionRef -} - -internal external interface AtomicFenceInfo : ExpressionInfo { - var order: Number -} - -internal external interface SIMDExtractInfo : ExpressionInfo { - var op: Operations - var vec: ExpressionRef - var index: ExpressionRef -} - -internal external interface SIMDReplaceInfo : ExpressionInfo { - var op: Operations - var vec: ExpressionRef - var index: ExpressionRef - var value: ExpressionRef -} - -internal external interface SIMDShuffleInfo : ExpressionInfo { - var left: ExpressionRef - var right: ExpressionRef - var mask: Array -} - -internal external interface SIMDTernaryInfo : ExpressionInfo { - var op: Operations - var a: ExpressionRef - var b: ExpressionRef - var c: ExpressionRef -} - -internal external interface SIMDShiftInfo : ExpressionInfo { - var op: Operations - var vec: ExpressionRef - var shift: ExpressionRef -} - -internal external interface SIMDLoadInfo : ExpressionInfo { - var op: Operations - var offset: Number - var align: Number - var ptr: ExpressionRef -} - -internal external interface MemoryInitInfo : ExpressionInfo { - var segment: Number - var dest: ExpressionRef - var offset: ExpressionRef - var size: ExpressionRef -} - -internal external interface MemoryDropInfo : ExpressionInfo { - var segment: Number -} - -internal external interface MemoryCopyInfo : ExpressionInfo { - var dest: ExpressionRef - var source: ExpressionRef - var size: ExpressionRef -} - -internal external interface MemoryFillInfo : ExpressionInfo { - var dest: ExpressionRef - var value: ExpressionRef - var size: ExpressionRef -} - -internal external interface RefNullInfo : ExpressionInfo - -internal external interface RefIsNullInfo : ExpressionInfo { - var value: ExpressionRef -} - -internal external interface RefFuncInfo : ExpressionInfo { - var func: String -} - -internal external interface TryInfo : ExpressionInfo { - var body: ExpressionRef - var catchBody: ExpressionRef -} - -internal external interface ThrowInfo : ExpressionInfo { - var event: String - var operands: Array -} - -internal external interface RethrowInfo : ExpressionInfo { - var exnref: ExpressionRef -} - -internal external interface BrOnExnInfo : ExpressionInfo { - var name: String - var event: String - var exnref: ExpressionRef -} - -internal external interface PopInfo : ExpressionInfo - -internal external interface PushInfo : ExpressionInfo { - var value: ExpressionRef -} - -internal external fun getFunctionInfo(func: FunctionRef): FunctionInfo - -internal external interface FunctionInfo { - var name: String - var module: String? - var base: String? - var params: Type - var results: Type - var vars: Array - var body: ExpressionRef -} - -internal external fun getGlobalInfo(global: GlobalRef): GlobalInfo - -internal external interface GlobalInfo { - var name: String - var module: String? - var base: String? - var type: Type - var mutable: Boolean - var init: ExpressionRef -} - -internal external fun getExportInfo(export_: ExportRef): ExportInfo - -internal external interface ExportInfo { - var kind: ExternalKinds - var name: String - var value: String -} - -internal external fun getEventInfo(event: EventRef): EventInfo - -internal external interface EventInfo { - var name: String - var module: String? - var base: String? - var attribute: Number - var params: Type - var results: Type -} - -internal external fun getSideEffects(expr: ExpressionRef, features: Features): SideEffects - -internal external enum class SideEffects { - None, - Branches, - Calls, - ReadsLocal, - WritesLocal, - ReadsGlobal, - WritesGlobal, - ReadsMemory, - WritesMemory, - ImplicitTrap, - IsAtomic, - Throws, - Any -} - -internal external fun emitText(expression: ExpressionRef): String - -internal external fun emitText(expression: Module): String - -internal external fun readBinary(data: Uint8Array): Module - -internal external fun parseText(text: String): Module - -internal external fun getOptimizeLevel(): Number - -internal external fun setOptimizeLevel(level: Number): Number - -internal external fun getShrinkLevel(): Number - -internal external fun setShrinkLevel(level: Number): Number - -internal external fun getDebugInfo(): Boolean - -internal external fun setDebugInfo(on: Boolean) - -internal external fun getLowMemoryUnused(): Boolean - -internal external fun setLowMemoryUnused(on: Boolean) - -internal external fun getPassArgument(key: String): String? - -internal external fun setPassArgument(key: String, value: String?) - -internal external fun clearPassArguments() - -internal external fun getAlwaysInlineMaxSize(): Number - -internal external fun setAlwaysInlineMaxSize(size: Number) - -internal external fun getFlexibleInlineMaxSize(): Number - -internal external fun setFlexibleInlineMaxSize(size: Number) - -internal external fun getOneCallerInlineMaxSize(): Number - -internal external fun setOneCallerInlineMaxSize(size: Number) - -internal external fun exit(status: Number) - -internal open external class Relooper(module: Module) { - open fun addBlock(expression: ExpressionRef): RelooperBlockRef - open fun addBranch(from: RelooperBlockRef, to: RelooperBlockRef, condition: ExpressionRef, code: ExpressionRef) - open fun addBlockWithSwitch(code: ExpressionRef, condition: ExpressionRef): RelooperBlockRef - open fun addBranchForSwitch( - from: RelooperBlockRef, - to: RelooperBlockRef, - indexes: Array, - code: ExpressionRef - ) - - open fun renderAndDispose(entry: RelooperBlockRef, labelHelper: Number): ExpressionRef -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt deleted file mode 100644 index eebfeb6ef..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("PackageDirectoryMismatch", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation") - -package space.kscience.kmath.internal.binaryen - -internal typealias Type = Number -internal typealias ExpressionRef = Number -internal typealias FunctionRef = Number -internal typealias GlobalRef = Number -internal typealias ExportRef = Number -internal typealias EventRef = Number -internal typealias RelooperBlockRef = Number diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt deleted file mode 100644 index 873a5e1d2..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:JsQualifier("WebAssembly") - -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", - "OVERRIDING_FINAL_MEMBER", - "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", - "ClassName", -) - -package space.kscience.kmath.internal.webassembly - -import space.kscience.kmath.internal.tsstdlib.PromiseLike -import org.khronos.webgl.ArrayBuffer -import org.khronos.webgl.ArrayBufferView -import org.khronos.webgl.Uint8Array -import org.w3c.fetch.Response -import kotlin.js.Promise - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface CompileError { - companion object { - var prototype: CompileError - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface Global { - var value: Any - fun valueOf(): Any - - companion object { - var prototype: Global - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -@JsName("Instance") -internal external interface Instance1 { - var exports: Exports - - companion object { - var prototype: Instance - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface LinkError { - companion object { - var prototype: LinkError - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface Memory { - var buffer: ArrayBuffer - fun grow(delta: Number): Number - - companion object { - var prototype: Memory - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -@JsName("Module") -internal external interface Module1 { - companion object { - var prototype: Module - fun customSections(moduleObject: Module, sectionName: String): Array - fun exports(moduleObject: Module): Array - fun imports(moduleObject: Module): Array - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface RuntimeError { - companion object { - var prototype: RuntimeError - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface Table { - var length: Number - fun get(index: Number): Function<*>? - fun grow(delta: Number): Number - fun set(index: Number, value: Function<*>?) - - companion object { - var prototype: Table - } -} - -internal external interface GlobalDescriptor { - var mutable: Boolean? - get() = definedExternally - set(value) = definedExternally - var value: String /* "f32" | "f64" | "i32" | "i64" */ -} - -internal external interface MemoryDescriptor { - var initial: Number - var maximum: Number? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ModuleExportDescriptor { - var kind: String /* "function" | "global" | "memory" | "table" */ - var name: String -} - -internal external interface ModuleImportDescriptor { - var kind: String /* "function" | "global" | "memory" | "table" */ - var module: String - var name: String -} - -internal external interface TableDescriptor { - var element: String /* "anyfunc" */ - var initial: Number - var maximum: Number? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface WebAssemblyInstantiatedSource { - var instance: Instance - var module: Module -} - -internal external fun compile(bytes: ArrayBufferView): Promise - -internal external fun compile(bytes: ArrayBuffer): Promise - -internal external fun compileStreaming(source: Response): Promise - -internal external fun compileStreaming(source: Promise): Promise - -internal external fun instantiate( - bytes: ArrayBufferView, - importObject: Imports = definedExternally, -): Promise - -internal external fun instantiate(bytes: ArrayBufferView): Promise - -internal external fun instantiate( - bytes: ArrayBuffer, - importObject: Imports = definedExternally, -): dynamic /* Promise | Promise */ - -internal external fun instantiate(bytes: ArrayBuffer): dynamic /* Promise | Promise */ - -internal external fun instantiate(moduleObject: Module, importObject: Imports = definedExternally): Promise - -internal external fun instantiate(moduleObject: Module): Promise - -internal external fun instantiateStreaming( - response: Response, - importObject: Imports = definedExternally, -): Promise - -internal external fun instantiateStreaming(response: Response): Promise - -internal external fun instantiateStreaming( - response: PromiseLike, - importObject: Imports = definedExternally, -): Promise - -internal external fun instantiateStreaming(response: PromiseLike): Promise - -internal external fun validate(bytes: ArrayBufferView): Boolean - -internal external fun validate(bytes: ArrayBuffer): Boolean - -internal external interface `T$0` { - var name: String - var kind: String -} - -internal external interface `T$1` { - var module: String - var name: String - var kind: String -} - -internal open external class Module { - constructor(bufferSource: ArrayBuffer) - constructor(bufferSource: Uint8Array) - - companion object { - fun customSections(module: Module, sectionName: String): Array - fun exports(module: Module): Array<`T$0`> - fun imports(module: Module): Array<`T$1`> - } -} - -@JsName("Instance") -internal open external class Instance(module: Module, importObject: dynamic = definedExternally) { - open var exports: dynamic -} - -@JsName("Memory") -internal open external class Memory1(memoryDescriptor: MemoryDescriptor) { - open var buffer: ArrayBuffer - open fun grow(numPages: Number): Number -} - -@JsName("Table") -internal open external class Table1(tableDescriptor: TableDescriptor) { - open var length: Number - open fun get(index: Number): Function<*> - open fun grow(numElements: Number): Number - open fun set(index: Number, value: Function<*>) -} - -internal external fun compile(bufferSource: Uint8Array): Promise - -internal external interface ResultObject { - var module: Module - var instance: Instance -} - -internal external fun instantiate( - bufferSource: Uint8Array, - importObject: Any = definedExternally, -): Promise - -internal external fun instantiate(bufferSource: Uint8Array): Promise - -internal external fun validate(bufferSource: Uint8Array): Boolean diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt deleted file mode 100644 index ba86e977b..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", - "OVERRIDING_FINAL_MEMBER", - "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", -) - -package space.kscience.kmath.internal.webassembly - -import space.kscience.kmath.internal.tsstdlib.Record - -internal typealias Exports = Record | Global | Memory | Table */> - -internal typealias ModuleImports = Record | Global | Memory | Table | Number */> - -internal typealias Imports = Record - -internal typealias CompileError1 = Error - -internal typealias LinkError1 = Error - -internal typealias RuntimeError1 = Error diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt deleted file mode 100644 index 1908f0659..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.wasm.internal - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.expressions.* -import space.kscience.kmath.internal.binaryen.* -import space.kscience.kmath.internal.webassembly.Instance -import space.kscience.kmath.operations.* -import space.kscience.kmath.internal.binaryen.Module as BinaryenModule -import space.kscience.kmath.internal.webassembly.Module as WasmModule - -private val spreader = eval("(obj, args) => obj(...args)") - -@OptIn(UnstableKMathAPI::class) -@Suppress("UnsafeCastFromDynamic") -internal sealed class WasmBuilder>( - protected val binaryenType: Type, - protected val algebra: Algebra, - protected val target: TypedMst, -) { - protected val keys: MutableList = mutableListOf() - protected lateinit var ctx: BinaryenModule - - abstract val instance: E - - protected val executable = run { - val c = WasmModule(with(createModule()) { - ctx = this - val expr = visit(target) - - addFunction( - "executable", - createType(Array(keys.size) { binaryenType }), - binaryenType, - arrayOf(), - expr - ) - - setOptimizeLevel(3) - optimizeFunction("executable") - addFunctionExport("executable", "executable") - val res = emitBinary() - dispose() - res - }) - - Instance(c, js("{}")).exports.executable - } - - protected abstract fun visitNumber(number: Number): ExpressionRef - - protected open fun visitVariable(node: TypedMst.Variable): ExpressionRef { - var idx = keys.indexOf(node.symbol) - - if (idx == -1) { - keys += node.symbol - idx = keys.lastIndex - } - - return ctx.local.get(idx, binaryenType) - } - - protected open fun visitUnary(node: TypedMst.Unary): ExpressionRef = - error("Unary operation ${node.operation} not defined in $this") - - protected open fun visitBinary(mst: TypedMst.Binary): ExpressionRef = - error("Binary operation ${mst.operation} not defined in $this") - - protected open fun createModule(): BinaryenModule = space.kscience.kmath.internal.binaryen.Module() - - protected fun visit(node: TypedMst): ExpressionRef = when (node) { - is TypedMst.Constant -> visitNumber( - node.number ?: error("Object constants are not supported by pritimive ASM builder"), - ) - - is TypedMst.Variable -> visitVariable(node) - is TypedMst.Unary -> visitUnary(node) - is TypedMst.Binary -> visitBinary(node) - } -} - -@UnstableKMathAPI -internal class DoubleWasmBuilder(target: TypedMst) : - WasmBuilder(f64, DoubleField, target) { - override val instance by lazy { - object : DoubleExpression { - override val indexer = SimpleSymbolIndexer(keys) - - override fun invoke(arguments: DoubleArray) = spreader(executable, arguments).unsafeCast() - } - } - - override fun createModule() = readBinary(f64StandardFunctions) - - override fun visitNumber(number: Number) = ctx.f64.const(number.toDouble()) - - override fun visitUnary(node: TypedMst.Unary): ExpressionRef = when (node.operation) { - GroupOps.MINUS_OPERATION -> ctx.f64.neg(visit(node.value)) - GroupOps.PLUS_OPERATION -> visit(node.value) - PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(node.value)) - TrigonometricOperations.SIN_OPERATION -> ctx.call("sin", arrayOf(visit(node.value)), f64) - TrigonometricOperations.COS_OPERATION -> ctx.call("cos", arrayOf(visit(node.value)), f64) - TrigonometricOperations.TAN_OPERATION -> ctx.call("tan", arrayOf(visit(node.value)), f64) - TrigonometricOperations.ASIN_OPERATION -> ctx.call("asin", arrayOf(visit(node.value)), f64) - TrigonometricOperations.ACOS_OPERATION -> ctx.call("acos", arrayOf(visit(node.value)), f64) - TrigonometricOperations.ATAN_OPERATION -> ctx.call("atan", arrayOf(visit(node.value)), f64) - ExponentialOperations.SINH_OPERATION -> ctx.call("sinh", arrayOf(visit(node.value)), f64) - ExponentialOperations.COSH_OPERATION -> ctx.call("cosh", arrayOf(visit(node.value)), f64) - ExponentialOperations.TANH_OPERATION -> ctx.call("tanh", arrayOf(visit(node.value)), f64) - ExponentialOperations.ASINH_OPERATION -> ctx.call("asinh", arrayOf(visit(node.value)), f64) - ExponentialOperations.ACOSH_OPERATION -> ctx.call("acosh", arrayOf(visit(node.value)), f64) - ExponentialOperations.ATANH_OPERATION -> ctx.call("atanh", arrayOf(visit(node.value)), f64) - ExponentialOperations.EXP_OPERATION -> ctx.call("exp", arrayOf(visit(node.value)), f64) - ExponentialOperations.LN_OPERATION -> ctx.call("log", arrayOf(visit(node.value)), f64) - else -> super.visitUnary(node) - } - - override fun visitBinary(mst: TypedMst.Binary): ExpressionRef = when (mst.operation) { - GroupOps.PLUS_OPERATION -> ctx.f64.add(visit(mst.left), visit(mst.right)) - GroupOps.MINUS_OPERATION -> ctx.f64.sub(visit(mst.left), visit(mst.right)) - RingOps.TIMES_OPERATION -> ctx.f64.mul(visit(mst.left), visit(mst.right)) - FieldOps.DIV_OPERATION -> ctx.f64.div(visit(mst.left), visit(mst.right)) - PowerOperations.POW_OPERATION -> ctx.call("pow", arrayOf(visit(mst.left), visit(mst.right)), f64) - else -> super.visitBinary(mst) - } -} - -@UnstableKMathAPI -internal class IntWasmBuilder(target: TypedMst) : WasmBuilder(i32, IntRing, target) { - override val instance by lazy { - object : IntExpression { - override val indexer = SimpleSymbolIndexer(keys) - - override fun invoke(arguments: IntArray) = spreader(executable, arguments).unsafeCast() - } - } - - override fun visitNumber(number: Number) = ctx.i32.const(number.toInt()) - - override fun visitUnary(node: TypedMst.Unary): ExpressionRef = when (node.operation) { - GroupOps.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(node.value)) - GroupOps.PLUS_OPERATION -> visit(node.value) - else -> super.visitUnary(node) - } - - override fun visitBinary(mst: TypedMst.Binary): ExpressionRef = when (mst.operation) { - GroupOps.PLUS_OPERATION -> ctx.i32.add(visit(mst.left), visit(mst.right)) - GroupOps.MINUS_OPERATION -> ctx.i32.sub(visit(mst.left), visit(mst.right)) - RingOps.TIMES_OPERATION -> ctx.i32.mul(visit(mst.left), visit(mst.right)) - else -> super.visitBinary(mst) - } -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt deleted file mode 100644 index d60f24247..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.wasm.internal - -import space.kscience.kmath.internal.base64.toUint8Array - -internal val f64StandardFunctions by lazy { toUint8Array(B) } - -private const val B = - "AGFzbQEAAAABMghgAABgAXwBfGACfHwBfGAFf39/f38Bf2ACfH8Bf2ADfHx/AXxgAnx/AXxgA39/fwF/AxsaAAEBAQEBAQIDBAUBAQEBAQEBAgYBAQUBAQcEBQFwAQEBBQMBAAIGFQN/AUGgnwQLfwBBoJ8EC38AQaAfCwclAwZtZW1vcnkCAAtfX2hlYXBfYmFzZQMBCl9fZGF0YV9lbmQDAgrpaxoCAAvPBQMBfgF/AnwCQAJAAkAgAL0iAUIgiKdB/////wdxIgJBgIDA/wNJDQAgAkGAgMCAfGogAadyRQ0BRAAAAAAAAAAAIAAgAKGjDwsCQAJAIAJB/////gNLDQBEGC1EVPsh+T8hAyACQYGAgOMDSQ0BRAdcFDMmppE8IAAgAKIiAyADIAMgAyADIANECff9DeE9Aj+iRIiyAXXg70k/oKJEO49otSiCpL+gokRVRIgOVcHJP6CiRH1v6wMS1tS/oKJEVVVVVVVVxT+goiADIAMgAyADRIKSLrHFuLM/okRZAY0bbAbmv6CiRMiKWZzlKgBAoKJESy2KHCc6A8CgokQAAAAAAADwP6CjIACioSAAoUQYLURU+yH5P6APCyABQn9XDQJEAAAAAAAA8D8gAKFEAAAAAAAA4D+iIgAgAJ8iBL1CgICAgHCDvyIDIAOioSAEIAOgoyAEIAAgACAAIAAgACAARAn3/Q3hPQI/okSIsgF14O9JP6CiRDuPaLUogqS/oKJEVUSIDlXByT+gokR9b+sDEtbUv6CiRFVVVVVVVcU/oKIgACAAIAAgAESCki6xxbizP6JEWQGNG2wG5r+gokTIilmc5SoAQKCiREstihwnOgPAoKJEAAAAAAAA8D+go6KgIAOgIgAgAKAhAwsgAw8LRBgtRFT7IQlARAAAAAAAAAAAIAFCAFMbDwtEGC1EVPsh+T8gAEQAAAAAAADwP6BEAAAAAAAA4D+iIgCfIgMgAyAAIAAgACAAIAAgAEQJ9/0N4T0CP6JEiLIBdeDvST+gokQ7j2i1KIKkv6CiRFVEiA5Vwck/oKJEfW/rAxLW1L+gokRVVVVVVVXFP6CiIAAgACAAIABEgpIuscW4sz+iRFkBjRtsBua/oKJEyIpZnOUqAECgokRLLYocJzoDwKCiRAAAAAAAAPA/oKOiRAdcFDMmppG8oKChIgAgAKALdwEBfwJAIAC9QjSIp0H/D3EiAUH/B0sNACAARAAAAAAAAPC/oCIAIAAgAKIgACAAoKCfoBARDwsCQCABQZgISw0AIAAgAKBEAAAAAAAA8L8gACAAokQAAAAAAADwv6CfIACgo6AQEA8LIAAQEETvOfr+Qi7mP6AL0gQDAX4BfwN8AkACQAJAAkACQCAAvSIBQiCIp0H/////B3EiAkGAgMD/A0kNACACQYCAwIB8aiABp3JFDQFEAAAAAAAAAAAgACAAoaMPCwJAIAJB/////gNLDQAgAkGAgEBqQYCAgPIDTw0CIAAPC0QAAAAAAADwPyAAmaFEAAAAAAAA4D+iIgAgACAAIAAgACAARAn3/Q3hPQI/okSIsgF14O9JP6CiRDuPaLUogqS/oKJEVUSIDlXByT+gokR9b+sDEtbUv6CiRFVVVVVVVcU/oKIgACAAIAAgAESCki6xxbizP6JEWQGNG2wG5r+gokTIilmc5SoAQKCiREstihwnOgPAoKJEAAAAAAAA8D+goyEDIACfIQQgAkGz5rz/A0kNAkQYLURU+yH5PyAEIAQgA6KgIgAgAKBEB1wUMyamkbygoSEADAMLIABEGC1EVPsh+T+iRAAAAAAAAHA4oA8LIAAgAKIiBCAEIAQgBCAEIARECff9DeE9Aj+iRIiyAXXg70k/oKJEO49otSiCpL+gokRVRIgOVcHJP6CiRH1v6wMS1tS/oKJEVVVVVVVVxT+goiAEIAQgBCAERIKSLrHFuLM/okRZAY0bbAbmv6CiRMiKWZzlKgBAoKJESy2KHCc6A8CgokQAAAAAAADwP6CjIACiIACgDwtEGC1EVPsh6T8gBL1CgICAgHCDvyIFIAWgoSAEIASgIAOiRAdcFDMmppE8IAAgBSAFoqEgBCAFoKMiACAAoKGhoUQYLURU+yHpP6AhAAsgAJogACABQgBTGwvbAQQBfwF+AX8BfCMAQRBrIgEkACAAvSICQv///////////wCDvyEAAkACQCACQjSIp0H/D3EiA0GZCEkNACAAEBBE7zn6/kIu5j+gIQAMAQsCQCADQYAISQ0AIAAgAKBEAAAAAAAA8D8gACAAokQAAAAAAADwP6CfIACgo6AQECEADAELAkAgA0HlB0kNACAAIACiIgQgBEQAAAAAAADwP6CfRAAAAAAAAPA/oKMgAKAQESEADAELIAEgAEQAAAAAAABwR6A5AwgLIAFBEGokACAAmiAAIAJCAFMbC6gEBAF/AX4DfwJ8IwBBEGshASAAvSICQj+IpyEDAkACQAJAIAJCIIinQf////8HcSIEQYCAwKAESQ0AIAJC////////////AINCgICAgICAgPj/AFYNAUQYLURU+yH5v0QYLURU+yH5PyADGw8LAkACQCAEQf//7/4DSw0AQX8hBSAEQf////EDSw0BIARB//8/Sw0CIAEgALY4AgwgAA8LIACZIQACQAJAAkAgBEH//8v/A0sNACAEQf//l/8DSw0BIAAgAKBEAAAAAAAA8L+gIABEAAAAAAAAAECgoyEAQQAhBQwDCyAEQf//jYAESw0BIABEAAAAAAAA+L+gIABEAAAAAAAA+D+iRAAAAAAAAPA/oKMhAEECIQUMAgsgAEQAAAAAAADwv6AgAEQAAAAAAADwP6CjIQBBASEFDAELRAAAAAAAAPC/IACjIQBBAyEFCyAAIAAgAKIiBiAGoiIHIAcgByAHIAdEL2xqLES0or+iRJr93lIt3q2/oKJEbZp0r/Kws7+gokRxFiP+xnG8v6CiRMTrmJmZmcm/oKIgBiAHIAcgByAHIAdEEdoi4zqtkD+iROsNdiRLe6k/oKJEUT3QoGYNsT+gokRuIEzFzUW3P6CiRP+DAJIkScI/oKJEDVVVVVVV1T+goqCiIQcgBUF/TA0BIAVBA3QiBEGACGorAwAgByAEQaAIaisDAKEgAKGhIgCaIAAgAxshAAsgAA8LIAAgB6ELtgEEAX8BfgF/AXwjAEEQayIBJAAgAL0iAkL///////////8Ag78hAAJAAkACQCACQjSIp0H/D3EiA0H9B0sNACADQd4HSw0BIAMNAiABIAC2OAIMDAILIABEAAAAAAAA8D8gAKGjIgAgAKAQEUQAAAAAAADgP6IhAAwBCyAAIACgIgQgBCAAokQAAAAAAADwPyAAoaOgEBFEAAAAAAAA4D+iIQALIAFBEGokACAAmiAAIAJCAFMbC5IBAQN8RAAAAAAAAPA/IAAgAKIiAkQAAAAAAADgP6IiA6EiBEQAAAAAAADwPyAEoSADoSACIAIgAiACRJAVyxmgAfo+okR3UcEWbMFWv6CiRExVVVVVVaU/oKIgAiACoiIDIAOiIAIgAkTUOIi+6fqovaJExLG0vZ7uIT6gokStUpyAT36SvqCioKIgACABoqGgoAuEFgYHfwF8Cn8BfAN/AnwjAEGwBGsiBSQAIAIgAkF9akEYbSIGQQAgBkEAShsiB0FobGohCAJAIARBAnRBwAhqKAIAIgkgA0F/aiICakEASA0AIAkgA2ohCiAHIAJrIQIgB0EBaiADa0ECdEHQCGohCyAFQcACaiEGA0ACQAJAIAJBAEgNACALKAIAtyEMDAELRAAAAAAAAAAAIQwLIAYgDDkDACAGQQhqIQYgC0EEaiELIAJBAWohAiAKQX9qIgoNAAsLIAhBaGohDQJAAkAgA0EBSA0AIAVBwAJqIANBA3RqQXhqIQ5BACEKA0BEAAAAAAAAAAAhDCAAIQIgAyELIA4hBgNAIAwgAisDACAGKwMAoqAhDCACQQhqIQIgBkF4aiEGIAtBf2oiCw0ACyAFIApBA3RqIAw5AwAgDkEIaiEOIAogCUghAiAKQQFqIQogAg0ADAILCyAFQQAgCUEAIAlBAEobQQN0QQhqEBkaC0EXIA1rIQ9BGCANayEQIAVB4ANqIAlBAnRqQXxqIREgBUHgA2pBfGohEiAFQXhqIRMgBUEIciEUIAkhBgN/IAUgBkEDdCIVaisDACEMAkAgBkEBSCIWDQAgEyAVaiECIAVB4ANqIQsgBiEKA0ACQAJAIAxEAAAAAAAAcD6iIheZRAAAAAAAAOBBYw0AQYCAgIB4IQ4MAQsgF6ohDgsCQAJAIAwgDrciF0QAAAAAAABwwaKgIgyZRAAAAAAAAOBBYw0AQYCAgIB4IQ4MAQsgDKohDgsgCyAONgIAIAtBBGohCyACKwMAIBegIQwgAkF4aiECIApBf2oiCg0ACwsCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAMIA0QEyIMIAxEAAAAAAAAwD+inEQAAAAAAAAgwKKgIgyZRAAAAAAAAOBBYw0AQYCAgIB4IRggDEGAgICAeLehIQwgDUEBSCIZRQ0BDAILIAwgDKoiGLehIQwgDUEBSCIZDQELIAVB4ANqIAZBAnRqQXxqIgIgAigCACICIAIgEHUiAiAQdGsiCzYCACACIBhqIRggCyAPdSIaQQFIDQIMAQsCQCANRQ0AQQIhGiAMRAAAAAAAAOA/ZkEBc0UNAUEAIRogDEQAAAAAAAAAAGENAwwECyAFQeADaiAGQQJ0akF8aigCAEEXdSIaQQFIDQELAkACQCAWDQBBACEWIAVB4ANqIQIgBiEOA0AgAigCACELQf///wchCgJAAkAgFg0AIAtFDQFBASEWQYCAgAghCgsgAiAKIAtrNgIAIAJBBGohAiAOQX9qIg4NAQwDC0EAIRYgAkEEaiECIA5Bf2oiDg0ADAILC0EAIRYLAkACQAJAIBkNACANQQJGDQEgDUEBRw0AIAVB4ANqIAZBAnRqQXxqIgIgAigCAEH///8DcTYCAAsgGEEBaiEYIBpBAkcNAgwBCyAFQeADaiAGQQJ0akF8aiICIAIoAgBB////AXE2AgAgGEEBaiEYIBpBAkcNAQtEAAAAAAAA8D8gDKEhDEECIRogFkUNACAMRAAAAAAAAPA/IA0QE6EiDEQAAAAAAAAAAGENAQwCCyAMRAAAAAAAAAAAYg0BCwJAIAYgCUwNACASIAZBAnRqIQJBACELIAYhCgNAIAIoAgAgC3IhCyACQXxqIQIgCkF/aiIKIAlKDQALIAsNAgsgESECIAYhDgNAIA5BAWohDiACKAIAIQsgAkF8aiECIAtFDQALIAZBAWohAgJAIANBAUgNACAFQcACaiADIAZqQQN0aiEWA0AgBUHAAmogBiADakEDdGogAiIKIAdqQQJ0QdAIaigCALc5AwBEAAAAAAAAAAAhDCAAIQIgFiEGIAMhCwNAIAwgAisDACAGKwMAoqAhDCACQQhqIQIgBkF4aiEGIAtBf2oiCw0ACyAFIApBA3RqIAw5AwAgFkEIaiEWIApBAWohAiAKIQYgCiAOSA0ADAsLCyAUIBVqQQAgDiACIA4gAkobIAZrQQN0EBkaIAcgBmpBAnRB1AhqIQIgBUHAAmogAyAGakEDdGohCwNAIAsgAigCALc5AwAgAkEEaiECIAtBCGohCyAGQQFqIgYgDkgNAAsgDiEGDAoLAkAgDEEAIA1rEBMiDEQAAAAAAABwQWZBAXNFDQAgDJlEAAAAAAAA4EFjDQJBgICAgHghAgwDCyAGQQJ0IQsgDEQAAAAAAABwPqIiF5lEAAAAAAAA4EFjDQNBgICAgHghAgwECyAFQeADaiAGQQJ0akF8aiECIA0hCANAIAZBf2ohBiAIQWhqIQggAigCACELIAJBfGohAiALRQ0AC0EAIQ4gBkEATg0FDAYLIAyqIQILIA0hCAwCCyAXqiECCyAFQeADaiALaiELAkACQCAMIAK3RAAAAAAAAHDBoqAiDJlEAAAAAAAA4EFjDQBBgICAgHghCgwBCyAMqiEKCyALIAo2AgAgBkEBaiEGCyAFQeADaiAGQQJ0aiACNgIAQQAhDiAGQQBIDQELIAZBAWohCkQAAAAAAADwPyAIEBMhDCAFQeADaiAGQQJ0aiECIAUgBkEDdGohCwNAIAsgDCACKAIAt6I5AwAgAkF8aiECIAtBeGohCyAMRAAAAAAAAHA+oiEMIApBf2oiCiAOSg0ACyAGQQBIDQAgBSAGQQN0aiEOIAYhAgNAIAYgAiIDayEWRAAAAAAAAAAAIQxBACECQQAhCwJAA0AgDCACQaAeaisDACAOIAJqKwMAoqAhDCALIAlODQEgAkEIaiECIAsgFkkhCiALQQFqIQsgCg0ACwsgBUGgAWogFkEDdGogDDkDACAOQXhqIQ4gA0F/aiECIANBAEoNAAsLAkACQAJAAkACQAJAAkACQCAEQX9qQQJJDQAgBEUNASAEQQNHDQdEAAAAAAAAAAAhGwJAIAZBAUgNACAFQaABaiAGQQN0aiILQXhqIQIgCysDACEMIAYhCwNAIAIgAisDACIcIAygIhc5AwAgAkEIaiAMIBwgF6GgOQMAIAJBeGohAiAXIQwgC0F/aiILQQBKDQALIAZBAkgNACAFQaABaiAGQQN0aiILQXhqIQIgCysDACEMIAYhCwNAIAIgAisDACIcIAygIhc5AwAgAkEIaiAMIBwgF6GgOQMAIAJBeGohAiAXIQwgC0F/aiILQQFKDQALIAZBAkgNACAFQaABaiAGQQN0aiECRAAAAAAAAAAAIRsDQCAbIAIrAwCgIRsgAkF4aiECIAZBf2oiBkEBSg0ACwsgBSsDoAEhDCAaRQ0EIAEgDJo5AwAgASAFKwOoAZo5AwggASAbmjkDEAwHCyAGQQBIDQEgBkEBaiELIAVBoAFqIAZBA3RqIQJEAAAAAAAAAAAhDANAIAwgAisDAKAhDCACQXhqIQIgC0F/aiILQQBKDQAMAwsLIAZBAEgNAyAGQQFqIQsgBUGgAWogBkEDdGohAkQAAAAAAAAAACEMA0AgDCACKwMAoCEMIAJBeGohAiALQX9qIgtBAEoNAAwFCwtEAAAAAAAAAAAhDAsgASAMmiAMIBobOQMAIAUrA6ABIAyhIQwCQCAGQQFIDQAgBUGgAWpBCHIhAgNAIAwgAisDAKAhDCACQQhqIQIgBkF/aiIGDQALCyABIAyaIAwgGhs5AwgMAwsgASAMOQMAIAEgBSkDqAE3AwggASAbOQMQDAILRAAAAAAAAAAAIQwLIAEgDJogDCAaGzkDAAsgBUGwBGokACAYQQdxDwsgDiEGDAALC8MKBgF/AX4DfwN8AX8BfCMAQTBrIgIkACAAvSIDQj+IpyEEAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADQiCIpyIFQf////8HcSIGQfrUvYAESw0AIAVB//8/cUH7wyRGDQMgBkH8souABEsNASAERQ0GIAEgAEQAAEBU+yH5P6AiAEQxY2IaYbTQPaAiBzkDACABIAAgB6FEMWNiGmG00D2gOQMIIAJBMGokAEF/DwsCQCAGQbuM8YAESw0AIAZBvPvXgARLDQIgBkH8ssuABEYNAyAERQ0KIAEgAEQAADB/fNkSQKAiAETKlJOnkQ7pPaAiBzkDACABIAAgB6FEypSTp5EO6T2gOQMIIAJBMGokAEF9DwsgBkH6w+SJBE0NAiAGQYCAwP8HSQ0DIAEgACAAoSIAOQMAIAEgADkDCCACQTBqJABBAA8LIARFDQUgASAARAAAQFT7IQlAoCIARDFjYhphtOA9oCIHOQMAIAEgACAHoUQxY2IaYbTgPaA5AwggAkEwaiQAQX4PCyAGQfvD5IAERw0CCyABIAAgAESDyMltMF/kP6JEAAAAAAAAOEOgRAAAAAAAADjDoCIHRAAAQFT7Ifm/oqAiCCAHRDFjYhphtNA9oiIJoSIAOQMAIAZBFHYiCiAAvUI0iKdB/w9xa0ERSCEFAkACQAJAIAeZRAAAAAAAAOBBYw0AQYCAgIB4IQYgBUUNAQwCCyAHqiEGIAUNAQsgASAIIAdEAABgGmG00D2iIgChIgsgB0RzcAMuihmjO6IgCCALoSAAoaEiCaEiADkDAAJAIAogAL1CNIinQf8PcWtBMkgNACABIAsgB0QAAAAuihmjO6IiAKEiCCAHRMFJICWag3s5oiALIAihIAChoSIJoSIAOQMADAELIAshCAsgASAIIAChIAmhOQMIIAJBMGokACAGDwsgA0L/////////B4NCgICAgICAgLDBAIS/IgCZRAAAAAAAAOBBYw0DQYCAgIB4IQUMBAsgBEUNBSABIABEAABAVPshGUCgIgBEMWNiGmG08D2gIgc5AwAgASAAIAehRDFjYhphtPA9oDkDCCACQTBqJABBfA8LIAEgAEQAAEBU+yH5v6AiAEQxY2IaYbTQvaAiBzkDACABIAAgB6FEMWNiGmG00L2gOQMIIAJBMGokAEEBDwsgASAARAAAQFT7IQnAoCIARDFjYhphtOC9oCIHOQMAIAEgACAHoUQxY2IaYbTgvaA5AwggAkEwaiQAQQIPCyAAqiEFCyACIAW3Igc5AxACQAJAIAAgB6FEAAAAAAAAcEGiIgCZRAAAAAAAAOBBYw0AQYCAgIB4IQUMAQsgAKohBQsgAiAFtyIHOQMYIAIgACAHoUQAAAAAAABwQaIiADkDICAARAAAAAAAAAAAYg0CIAJBEGpBCHIhBUECIQoDQCAKQX9qIQogBSsDACEAIAVBeGohBSAARAAAAAAAAAAAYQ0ADAQLCyABIABEAAAwf3zZEsCgIgBEypSTp5EO6b2gIgc5AwAgASAAIAehRMqUk6eRDum9oDkDCCACQTBqJABBAw8LIAEgAEQAAEBU+yEZwKAiAEQxY2IaYbTwvaAiBzkDACABIAAgB6FEMWNiGmG08L2gOQMIIAJBMGokAEEEDwtBAiEKCyACQRBqIAIgBkEUdkHqd2ogCkEBakEBEAghBSACKwMAIQACQCAERQ0AIAEgAJo5AwAgASACKwMImjkDCCACQTBqJABBACAFaw8LIAEgADkDACABIAIpAwg3AwggAkEwaiQAIAULmwEBA3wgACAAoiIDIAMgA6KiIANEfNXPWjrZ5T2iROucK4rm5Vq+oKIgAyADRH3+sVfjHcc+okTVYcEZoAEqv6CiRKb4EBEREYE/oKAhBCADIACiIQUCQCACRQ0AIAAgBURJVVVVVVXFP6IgAyABRAAAAAAAAOA/oiAFIASioaIgAaGgoQ8LIAUgAyAEokRJVVVVVVXFv6CiIACgC5ICAgJ/AXwjAEEQayIBJAACQAJAAkAgAL1CIIinQf////8HcSICQfvDpP8DSw0AIAJBncGa8gNLDQEgASAARAAAAAAAAHBHoDkDACABQRBqJABEAAAAAAAA8D8PCyACQYCAwP8HSQ0BIAFBEGokACAAIAChDwsgAEQAAAAAAAAAABAHIQAgAUEQaiQAIAAPCyAAIAEQCSECIAErAwghACABKwMAIQMCQAJAAkAgAkEDcSICQQJGDQAgAkEBRg0BIAINAiADIAAQByEAIAFBEGokACAADwsgAyAAEAchACABQRBqJAAgAJoPCyADIABBARAKIQAgAUEQaiQAIACaDwsgAyAAQQEQCiEAIAFBEGokACAACyQAIABEi90aFWYglsCgEA5EAAAAAAAAwH+iRAAAAAAAAMB/ogvaAQMBfwF+AX8jAEEQayIBJAAgAL1C////////////AIMiAr8hAAJAAkACQCACQiCIpyIDQcHcmP8DSw0AIANB//+/8gNLDQEgASAARAAAAAAAAHBHoDkDCCABQRBqJABEAAAAAAAA8D8PCyADQcHcmIQESw0BIAAQDiEAIAFBEGokACAARAAAAAAAAPA/IACjoEQAAAAAAADgP6IPCyABQRBqJAAgABAPIgAgAKIgAEQAAAAAAADwP6AiACAAoKNEAAAAAAAA8D+gDwsgABAMIQAgAUEQaiQAIAALoAQEAX8BfgJ/A3wjAEEQayIBJAAgAL0iAkI/iKchAwJAAkACQAJAAkACQAJAAkACQAJAIAJCIIinQf////8HcSIEQavGmIQESQ0AIAJC////////////AINCgICAgICAgPj/AFgNASABQRBqJAAgAA8LIARBw9zY/gNJDQEgBEGyxcL/A08NAyADQQFzIANrIQQMBgsgAETvOfr+Qi6GQGRBAXMNASABQRBqJAAgAEQAAAAAAADgf6IPCyAEQYCAwPEDTQ0CQQAhBEQAAAAAAAAAACEFIAAhBgwFCyAARNK8et0rI4bAY0EBcw0AIAFEAAAAAAAAoLYgAKO2OAIMRAAAAAAAAAAAIQcgAERRMC3VEEmHwGMNBQsgAET+gitlRxX3P6IgA0EDdEHgHmorAwCgIgeZRAAAAAAAAOBBYw0BQYCAgIB4IQQMAgsgASAARAAAAAAAAOB/oDkDACABQRBqJAAgAEQAAAAAAADwP6APCyAHqiEECyAAIAS3IgdEAADg/kIu5r+ioCIAIAdEdjx5Ne856j2iIgWhIQYLIAAgBiAGIAYgBqIiByAHIAcgByAHRNCkvnJpN2Y+okTxa9LFQb27vqCiRCzeJa9qVhE/oKJEk72+FmzBZr+gokQ+VVVVVVXFP6CioSIHokQAAAAAAAAAQCAHoaMgBaGgRAAAAAAAAPA/oCEHIARFDQAgByAEEBMhBwsgAUEQaiQAIAcL2QYEAX8BfgJ/BHwjAEEQayEBIAC9IgJCP4inIQMCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCACQiCIp0H/////B3EiBEH60I2CBEkNACACQv///////////wCDQoCAgICAgID4/wBYDQEgAA8LIARBw9zY/gNJDQEgBEGxxcL/A0sNAiADRQ0GIABEAADg/kIu5j+gIQVBfyEERHY8eTXvOeq9IQYMCgsgA0UNA0QAAAAAAADwvw8LIARB//+/5ANLDQEgBEH//z9LDQMgASAAtjgCDCAADwsgAET+gitlRxX3P6IhBkQAAAAAAADgvyEFIAMNBgwFC0EAIQQMBwsgAETvOfr+Qi6GQGRFDQIgAEQAAAAAAADgf6IPCyAADwsgAEQAAOD+Qi7mv6AhBUEBIQREdjx5Ne856j0hBgwDCyAARP6CK2VHFfc/oiEGC0QAAAAAAADgPyEFCwJAAkAgBiAFoCIFmUQAAAAAAADgQWMNAEGAgICAeCEEDAELIAWqIQQLIAS3IgVEdjx5Ne856j2iIQYgACAFRAAA4P5CLua/oqAhBQsgBSAFIAahIgChIAahIQYLIAAgAEQAAAAAAADgP6IiB6IiBSAFIAUgBSAFIAVELcMJbrf9ir6iRDlS5obKz9A+oKJEt9uqnhnOFL+gokSFVf4ZoAFaP6CiRPQQEREREaG/oKJEAAAAAAAA8D+gIghEAAAAAAAACEAgByAIoqEiB6FEAAAAAAAAGEAgACAHoqGjoiEHAkACQAJAAkACQCAERQ0AIAAgByAGoaIgBqEgBaEhBSAEQQFGDQEgBEF/Rw0CIAAgBaFEAAAAAAAA4D+iRAAAAAAAAOC/oA8LIAAgACAHoiAFoaEPCyAARAAAAAAAANC/Y0EBcw0BIAUgAEQAAAAAAADgP6ChRAAAAAAAAADAog8LIARB/wdqrUI0hr8hBiAEQTlJDQEgACAFoUQAAAAAAADwP6AiACAAoEQAAAAAAADgf6IgACAGoiAEQYAIRhtEAAAAAAAA8L+gDwsgACAFoSIAIACgRAAAAAAAAPA/oA8LRAAAAAAAAPA/Qf8HIARrrUI0hr8iB6EgACAFIAegoSAEQRRIIgQbIAAgBaFEAAAAAAAA8D8gBBugIAaiC6IDAwF+A38CfAJAAkACQAJAAkAgAL0iAUIAUw0AIAFCIIinIgJB//8/TQ0AIAJB//+//wdLDQNBgIDA/wMhA0GBeCEEIAJBgIDA/wNHDQEgAacNAkQAAAAAAAAAAA8LAkAgAUL///////////8Ag0IAUQ0AIAFCf1cNBCAARAAAAAAAAFBDor0iAUIgiKchA0HLdyEEDAILRAAAAAAAAPC/IAAgAKKjDwsgAiEDCyAEIANB4r4laiICQRR2arciBUQAAOD+Qi7mP6IgAkH//z9xQZ7Bmv8Daq1CIIYgAUL/////D4OEv0QAAAAAAADwv6AiACAFRHY8eTXvOeo9oiAAIABEAAAAAAAAAECgoyIFIAAgAEQAAAAAAADgP6KiIgYgBSAFoiIFIAWiIgAgACAARJ/GeNAJmsM/okSveI4dxXHMP6CiRAT6l5mZmdk/oKIgBSAAIAAgAEREUj7fEvHCP6JE3gPLlmRGxz+gokRZkyKUJEnSP6CiRJNVVVVVVeU/oKKgoKKgIAahoKAhAAsgAA8LIAAgAKFEAAAAAAAAAACjC4kEBAF/AX4BfwN8IwBBEGshASAAvSICQiCIpyEDAkACQAJAAkACQCACQgBTDQAgA0H5hOr+A00NACADQf//v/8HTQ0BIAAPCwJAIANBgIDA/3tJDQAgAEQAAAAAAADwv2INA0QAAAAAAADw/w8LAkAgA0EBdEH////JB0sNACADQYCAwP8HcUUNBCAADwtEAAAAAAAAAAAhBCADQcX9yv57Tw0ARAAAAAAAAAAAIQUMAQtEAAAAAAAAAAAhBAJAIABEAAAAAAAA8D+gIgW9IgJCIIinQeK+JWoiAUEUdkGBeGoiA0E1Sg0AIAAgBaFEAAAAAAAA8D+gIAAgBUQAAAAAAADwv6ChIANBAUobIAWjIQQLIAFB//8/cUGewZr/A2qtQiCGIAJC/////w+DhL9EAAAAAAAA8L+gIQAgA7chBQsgBUQAAOD+Qi7mP6IgACAEIAVEdjx5Ne856j2ioCAAIABEAAAAAAAAAECgoyIFIAAgAEQAAAAAAADgP6KiIgYgBSAFoiIEIASiIgUgBSAFRJ/GeNAJmsM/okSveI4dxXHMP6CiRAT6l5mZmdk/oKIgBCAFIAUgBUREUj7fEvHCP6JE3gPLlmRGxz+gokRZkyKUJEnSP6CiRJNVVVVVVeU/oKKgoKKgIAahoKAPCyAAIAChRAAAAAAAAAAAow8LIAEgALY4AgwgAAvHEAYBfAF+A38BfgV/CHxEAAAAAAAA8D8hAgJAIAG9IgNCIIinIgRB/////wdxIgUgA6ciBnJFDQAgAL0iB0IgiKchCAJAIAenIgkNACAIQYCAwP8DRg0BCwJAAkAgCEH/////B3EiCkGAgMD/B0sNACAJQQBHIApBgIDA/wdGcQ0AIAVBgIDA/wdLDQAgBkUNASAFQYCAwP8HRw0BCyAAIAGgDwtBACELAkACQAJAAkAgCEF/Sg0AQQIhCyAFQf///5kESw0AQQAhCyAFQYCAwP8DSQ0AIAVBFHYhDCAFQYCAgIoESQ0BQQIgBkGzCCAMayILdiIMQQFxa0EAIAwgC3QgBkYbIQsLIAZFDQEMAgtBACELIAYNAUECIAVBkwggDGsiBnYiC0EBcWtBACALIAZ0IAVGGyELCwJAAkACQAJAIAVBgIDA/wdHDQAgCkGAgMCAfGogCXJFDQUgCkGAgMD/A0kNASABRAAAAAAAAAAAIARBf0obDwsCQCAFQYCAwP8DRw0AIARBf0wNAyAADwsgBEGAgICABEcNASAAIACiDwtEAAAAAAAAAAAgAZogBEF/ShsPCyAIQQBIDQEgBEGAgID/A0cNASAAnw8LRAAAAAAAAPA/IACjDwsgAJkhAgJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAkNACAKRQ0BIApBgICAgARyQYCAwP8HRg0BC0QAAAAAAADwPyENIAhBf0oNAyALQQFGDQEgCw0DIAAgAKEiASABow8LRAAAAAAAAPA/IAKjIAIgBEEASBshAiAIQX9KDQsgCyAKQYCAwIB8anJFDQEgApogAiALQQFGGw8LRAAAAAAAAPC/IQ0gBUGBgICPBE8NAgwDCyACIAKhIgEgAaMPCyAFQYGAgI8ESQ0BCwJAIAVBgYDAnwRJDQAgCkH//7//A0sNAkQAAAAAAADwf0QAAAAAAAAAACAEQQBIGw8LIApB/v+//wNLDQIgDUScdQCIPOQ3fqJEnHUAiDzkN36iIA1EWfP4wh9upQGiRFnz+MIfbqUBoiAEQQBIGw8LQQAhBQJAAkAgCkH//z9LDQAgAkQAAAAAAABAQ6IiAr1CIIinIQpBSyEEDAELQQAhBAsgCkH//z9xIgZBgIDA/wNyIQggCkEUdSAEakGBeGohBCAGQY+xDkkNAyAGQfrsLk8NAkEBIQUMAwtEAAAAAAAA8H9EAAAAAAAAAAAgBEEAShsPCyAKQYGAwP8DSQ0CIA1EnHUAiDzkN36iRJx1AIg85Dd+oiANRFnz+MIfbqUBokRZ8/jCH26lAaIgBEEAShsPCyAIQYCAQGohCCAEQQFqIQQLIAVBA3QiBkGQH2orAwAiDiAIrUIghiACvUL/////D4OEvyIPIAZB8B5qKwMAIhChIhFEAAAAAAAA8D8gECAPoKMiEqIiAr1CgICAgHCDvyIAIAAgAKIiE0QAAAAAAAAIQKAgAiAAoCASIBEgACAIQQF1QYCAgIACciAFQRJ0akGAgCBqrUIghr8iFKKhIAAgDyAUIBChoaKhoiIPoiACIAKiIgAgAKIgACAAIAAgACAARO9ORUoofso/okRl28mTSobNP6CiRAFBHalgdNE/oKJETSaPUVVV1T+gokT/q2/btm3bP6CiRAMzMzMzM+M/oKKgIhCgvUKAgICAcIO/IgCiIhEgDyAAoiACIBAgAEQAAAAAAAAIwKAgE6GhoqAiAqC9QoCAgIBwg78iAEQAAADgCcfuP6IiDyAGQYAfaisDACACIAAgEaGhRP0DOtwJx+4/oiAARPUBWxTgLz6+oqCgIhCgoCAEtyICoL1CgICAgHCDvyIAIAKhIA6hIA+hIQ4MAQsgAkQAAAAAAADwv6AiAEQAAABgRxX3P6IiAiAARETfXfgLrlQ+oiAAIACiRAAAAAAAAOA/IAAgAEQAAAAAAADQv6JEVVVVVVVV1T+goqGiRP6CK2VHFfe/oqAiEKC9QoCAgIBwg78iACACoSEOCyAAIANCgICAgHCDvyIPoiICIBAgDqEgAaIgASAPoSAAoqAiAaAiAL0iA6chBQJAAkACQAJAAkAgA0IgiKciCEGAgMCEBEgNACAIQYCAwPt7aiAFckUNASANRJx1AIg85Dd+okScdQCIPOQ3fqIPCyAIQYD4//8HcUGAmMOEBEkNAiAIQYDovPsDaiAFckUNASANRFnz+MIfbqUBokRZ8/jCH26lAaIPCyABRP6CK2VHFZc8oCAAIAKhZEEBcw0BIA1EnHUAiDzkN36iRJx1AIg85Dd+og8LIAEgACACoWVBAXNFDQELQQAhBQJAIAhB/////wdxIgZBgYCA/wNJDQBBAEGAgMAAIAZBFHZBgnhqdiAIaiIGQf//P3FBgIDAAHJBkwggBkEUdkH/D3EiBGt2IgVrIAUgCEEASBshBSABIAJBgIBAIARBgXhqdSAGca1CIIa/oSICoL0hAwsCQCAFQRR0IANCgICAgHCDvyIARAAAAABDLuY/oiIPIAEgACACoaFE7zn6/kIu5j+iIABEOWyoDGFcIL6ioCICoCIBIAEgASABIAGiIgAgACAAIAAgAETQpL5yaTdmPqJE8WvSxUG9u76gokQs3iWvalYRP6CiRJO9vhZswWa/oKJEPlVVVVVVxT+goqEiAKIgAEQAAAAAAAAAwKCjIAIgASAPoaEiACABIACioKGhRAAAAAAAAPA/oCIBvSIDQiCIp2oiCEH//z9KDQAgDSABIAUQE6IPCyANIAitQiCGIANC/////w+DhL+iDwsgDURZ8/jCH26lAaJEWfP4wh9upQGiDwsgAgu4AQEBfwJAAkACQAJAIAFBgAhIDQAgAEQAAAAAAADgf6IhACABQYF4aiICQYAISA0BIAFBgnBqIgFB/wcgAUH/B0gbIQEgAEQAAAAAAADgf6IhAAwDCyABQYF4Sg0CIABEAAAAAAAAYAOiIQAgAUHJB2oiAkGBeEoNASABQZIPaiIBQYJ4IAFBgnhKGyEBIABEAAAAAAAAYAOiIQAMAgsgAiEBDAELIAIhAQsgACABQf8Haq1CNIa/oguiAgICfwF8IwBBEGsiASQAAkACQAJAIAC9QiCIp0H/////B3EiAkH7w6T/A0sNACACQf//v/IDSw0BIAEgAEQAAAAAAABwOKIgAEQAAAAAAABwR6AgAkGAgMAASRs5AwAgAUEQaiQAIAAPCyACQYCAwP8HSQ0BIAFBEGokACAAIAChDwsgAEQAAAAAAAAAAEEAEAohACABQRBqJAAgAA8LIAAgARAJIQIgASsDCCEAIAErAwAhAwJAAkACQCACQQNxIgJBAkYNACACQQFGDQEgAg0CIAMgAEEBEAohACABQRBqJAAgAA8LIAMgAEEBEAohACABQRBqJAAgAJoPCyADIAAQByEAIAFBEGokACAADwsgAyAAEAchACABQRBqJAAgAJoLrgEDAX4CfAF/RAAAAAAAAOC/RAAAAAAAAOA/IAC9IgFCAFMbIQIgAUL///////////8AgyIBvyEDAkACQAJAIAFCIIinIgRBwdyYhARLDQAgAxAPIQMgBEH//7//A0sNAiAEQYCAwPIDSQ0BIAIgAyADoCADIAOiIANEAAAAAAAA8D+go6GiDwsgAiACoCADEAyiIQALIAAPCyACIAMgAyADRAAAAAAAAPA/oKOgoguwAwMBfgJ/A3wCQAJAIAC9IgNCgICAgID/////AINCgYCAgPCE5fI/VCIEDQBEGC1EVPsh6T8gAJogACADQj+IpyIFG6FEB1wUMyamgTwgAZogASAFG6GgIQBEAAAAAAAAAAAhAQwBCwsgACAAIAAgAKIiBqIiB0RjVVVVVVXVP6IgASAGIAEgByAGIAaiIgggCCAIIAggCERzU2Dby3XzvqJEppI3oIh+FD+gokQBZfLy2ERDP6CiRCgDVskibW0/oKJEN9YGhPRklj+gokR6/hARERHBP6AgBiAIIAggCCAIIAhE1Hq/dHAq+z6iROmn8DIPuBI/oKJEaBCNGvcmMD+gokQVg+D+yNtXP6CiRJOEbunjJoI/oKJE/kGzG7qhqz+goqCioKKgoCIGoCEIAkAgBA0AQQEgAkEBdGu3IgEgACAGIAggCKIgCCABoKOhoCIIIAigoSIImiAIIAUbDwsCQCACRQ0ARAAAAAAAAPC/IAijIgEgCL1CgICAgHCDvyIHIAG9QoCAgIBwg78iCKJEAAAAAAAA8D+gIAYgByAAoaEgCKKgoiAIoCEICyAIC8EBAQJ/IwBBEGsiASQAAkACQAJAIAC9QiCIp0H/////B3EiAkH7w6T/A0sNACACQf////EDSw0BIAEgAEQAAAAAAABwOKIgAEQAAAAAAABwR6AgAkGAgMAASRs5AwAgAUEQaiQAIAAPCyACQYCAwP8HSQ0BIAFBEGokACAAIAChDwsgAEQAAAAAAAAAAEEAEBYhACABQRBqJAAgAA8LIAAgARAJIQIgASsDACABKwMIIAJBAXEQFiEAIAFBEGokACAAC4ACAwF/An4BfyMAQRBrIgEkACAAvSICQv///////////wCDIgO/IQACQAJAAkACQCADQiCIpyIEQeunhv8DSQ0AIARBgYDQgQRJDQFEAAAAAAAAAIAgAKNEAAAAAAAA8D+gIQAMAwsgBEGvscH+A0kNASAAIACgEA8iACAARAAAAAAAAABAoKMhAAwCC0QAAAAAAADwP0QAAAAAAAAAQCAAIACgEA9EAAAAAAAAAECgo6EhAAwBCwJAIARBgIDAAEkNACAARAAAAAAAAADAohAPIgCaIABEAAAAAAAAAECgoyEADAELIAEgALY4AgwLIAFBEGokACAAmiAAIAJCAFMbC/wCAgN/AX4CQCACRQ0AIAAgAToAACAAIAJqIgNBf2ogAToAACACQQNJDQAgACABOgACIAAgAToAASADQX1qIAE6AAAgA0F+aiABOgAAIAJBB0kNACAAIAE6AAMgA0F8aiABOgAAIAJBCUkNACAAQQAgAGtBA3EiBGoiAyABQf8BcUGBgoQIbCIBNgIAIAMgAiAEa0F8cSIEaiICQXxqIAE2AgAgBEEJSQ0AIAMgATYCCCADIAE2AgQgAkF4aiABNgIAIAJBdGogATYCACAEQRlJDQAgAyABNgIQIAMgATYCDCADIAE2AhQgAyABNgIYIAJBaGogATYCACACQWRqIAE2AgAgAkFsaiABNgIAIAJBcGogATYCACAEIANBBHFBGHIiBWsiAkEgSQ0AIAGtIgZCIIYgBoQhBiADIAVqIQEDQCABIAY3AwAgAUEIaiAGNwMAIAFBEGogBjcDACABQRhqIAY3AwAgAUEgaiEBIAJBYGoiAkEfSw0ACwsgAAsLqBcBAEGACAugF0+7YQVnrN0/GC1EVPsh6T+b9oHSC3PvPxgtRFT7Ifk/4mUvIn8rejwHXBQzJqaBPL3L8HqIB3A8B1wUMyamkTwDAAAABAAAAAQAAAAGAAAAg/miAERObgD8KRUA0VcnAN009QBi28AAPJmVAEGQQwBjUf4Au96rALdhxQA6biQA0k1CAEkG4AAJ6i4AHJLRAOsd/gApsRwA6D6nAPU1ggBEuy4AnOmEALQmcABBfl8A1pE5AFODOQCc9DkAi1+EACj5vQD4HzsA3v+XAA+YBQARL+8AClqLAG0fbQDPfjYACcsnAEZPtwCeZj8ALepfALondQDl68cAPXvxAPc5BwCSUooA+2vqAB+xXwAIXY0AMANWAHv8RgDwq2sAILzPADb0mgDjqR0AXmGRAAgb5gCFmWUAoBRfAI1AaACA2P8AJ3NNAAYGMQDKVhUAyahzAHviYABrjMAAGcRHAM1nwwAJ6NwAWYMqAIt2xACmHJYARK/dABlX0QClPgUABQf/ADN+PwDCMugAmE/eALt9MgAmPcMAHmvvAJ/4XgA1HzoAf/LKAPGHHQB8kCEAaiR8ANVu+gAwLXcAFTtDALUUxgDDGZ0ArcTCACxNQQAMAF0Ahn1GAONxLQCbxpoAM2IAALTSfAC0p5cAN1XVANc+9gCjEBgATXb8AGSdKgBw16sAY3z4AHqwVwAXFecAwElWADvW2QCnhDgAJCPLANaKdwBaVCMAAB+5APEKGwAZzt8AnzH/AGYeagCZV2EArPtHAH5/2AAiZbcAMuiJAOa/YADvxM0AbDYJAF0/1AAW3tcAWDveAN6bkgDSIigAKIboAOJYTQDGyjIACOMWAOB9ywAXwFAA8x2nABjgWwAuEzQAgxJiAINIAQD1jlsArbB/AB7p8gBISkMAEGfTAKrd2ACuX0IAamHOAAoopADTmbQABqbyAFx3fwCjwoMAYTyIAIpzeACvjFoAb9e9AC2mYwD0v8sAjYHvACbBZwBVykUAytk2ACio0gDCYY0AEsl3AAQmFAASRpsAxFnEAMjFRABNspEAABfzANRDrQApSeUA/dUQAAC+/AAelMwAcM7uABM+9QDs8YAAs+fDAMf4KACTBZQAwXE+AC4JswALRfMAiBKcAKsgewAutZ8AR5LCAHsyLwAMVW0AcqeQAGvnHwAxy5YAeRZKAEF54gD034kA6JSXAOLmhACZMZcAiO1rAF9fNgC7/Q4ASJq0AGekbABxckIAjV0yAJ8VuAC85QkAjTElAPd0OQAwBRwADQwBAEsIaAAs7lgAR6qQAHTnAgC91iQA932mAG5IcgCfFu8AjpSmALSR9gDRU1EAzwryACCYMwD1S34AsmNoAN0+XwBAXQMAhYl/AFVSKQA3ZMAAbdgQADJIMgBbTHUATnHUAEVUbgALCcEAKvVpABRm1QAnB50AXQRQALQ72wDqdsUAh/kXAElrfQAdJ7oAlmkpAMbMrACtFFQAkOJqAIjZiQAsclAABKS+AHcHlADzMHAAAPwnAOpxqABmwkkAZOA9AJfdgwCjP5cAQ5T9AA2GjAAxQd4AkjmdAN1wjAAXt+cACN87ABU3KwBcgKAAWoCTABARkgAP6NgAbICvANv/SwA4kA8AWRh2AGKlFQBhy7sAx4m5ABBAvQDS8gQASXUnAOu29gDbIrsAChSqAIkmLwBkg3YACTszAA6UGgBROqoAHaPCAK/trgBcJhIAbcJNAC16nADAVpcAAz+DAAnw9gArQIwAbTGZADm0BwAMIBUA2MNbAPWSxADGrUsATsqlAKc3zQDmqTYAq5KUAN1CaAAZY94AdozvAGiLUgD82zcArqGrAN8VMQAArqEADPvaAGRNZgDtBbcAKWUwAFdWvwBH/zoAavm5AHW+8wAok98Aq4AwAGaM9gAEyxUA+iIGANnkHQA9s6QAVxuPADbNCQBOQukAE76kADMjtQDwqhoAT2WoANLBpQALPw8AW3jNACP5dgB7iwQAiRdyAMamUwBvbuIA7+sAAJtKWADE2rcAqma6AHbPzwDRAh0AsfEtAIyZwQDDrXcAhkjaAPddoADGgPQArPAvAN3smgA/XLwA0N5tAJDHHwAq27YAoyU6AACvmgCtU5MAtlcEACkttABLgH4A2genAHaqDgB7WaEAFhIqANy3LQD65f0Aidv+AIm+/QDkdmwABqn8AD6AcACFbhUA/Yf/ACg+BwBhZzMAKhiGAE296gCz568Aj21uAJVnOQAxv1sAhNdIADDfFgDHLUMAJWE1AMlwzgAwy7gAv2z9AKQAogAFbOQAWt2gACFvRwBiEtIAuVyEAHBhSQBrVuAAmVIBAFBVNwAe1bcAM/HEABNuXwBdMOQAhS6pAB2ywwChMjYACLekAOqx1AAW9yEAj2nkACf/dwAMA4AAjUAtAE/NoAAgpZkAs6LTAC9dCgC0+UIAEdrLAH2+0ACb28EAqxe9AMqigQAIalwALlUXACcAVQB/FPAA4QeGABQLZACWQY0Ah77eANr9KgBrJbYAe4k0AAXz/gC5v54AaGpPAEoqqABPxFoALfi8ANdamAD0x5UADU2NACA6pgCkV18AFD+xAIA4lQDMIAEAcd2GAMnetgC/YPUATWURAAEHawCMsKwAssDQAFFVSAAe+w4AlXLDAKMGOwDAQDUABtx7AOBFzABOKfoA1srIAOjzQQB8ZN4Am2TYANm+MQCkl8MAd1jUAGnjxQDw2hMAujo8AEYYRgBVdV8A0r31AG6SxgCsLl0ADkTtABw+QgBhxIcAKf3pAOfW8wAifMoAb5E1AAjgxQD/140AbmriALD9xgCTCMEAfF10AGutsgDNbp0APnJ7AMYRagD3z6kAKXPfALXJugC3AFEA4rINAHS6JADlfWAAdNiKAA0VLACBGAwAfmaUAAEpFgCfenYA/f2+AFZF7wDZfjYA7NkTAIu6uQDEl/wAMagnAPFuwwCUxTYA2KhWALSotQDPzA4AEoktAG9XNAAsVokAmc7jANYguQBrXqoAPiqcABFfzAD9C0oA4fT7AI47bQDihiwA6dSEAPy0qQDv7tEALjXJAC85YQA4IUQAG9nIAIH8CgD7SmoALxzYAFO0hABOmYwAVCLMACpV3ADAxtYACxmWABpwuABplWQAJlpgAD9S7gB/EQ8A9LURAPzL9QA0vC0ANLzuAOhdzADdXmAAZ46bAJIz7wDJF7gAYVibAOFXvABRg8YA2D4QAN1xSAAtHN0ArxihACEsRgBZ89cA2XqYAJ5UwABPhvoAVgb8AOV5rgCJIjYAOK0iAGeT3ABV6KoAgiY4AMrnmwBRDaQAmTOxAKnXDgBpBUgAZbLwAH+IpwCITJcA+dE2ACGSswB7gkoAmM8hAECf3ADcR1UA4XQ6AGfrQgD+nd8AXtRfAHtnpAC6rHoAVfaiACuIIwBBulUAWW4IACEqhgA5R4MAiePmAOWe1ABJ+0AA/1bpABwPygDFWYoAlPorANPBxQAPxc8A21quAEfFhgCFQ2IAIYY7ACx5lAAQYYcAKkx7AIAsGgBDvxIAiCaQAHg8iQCoxOQA5dt7AMQ6wgAm9OoA92eKAA2SvwBloysAPZOxAL18CwCkUdwAJ91jAGnh3QCalBkAqCmVAGjOKAAJ7bQARJ8gAE6YygBwgmMAfnwjAA+5MgCn9Y4AFFbnACHxCAC1nSoAb35NAKUZUQC1+asAgt/WAJbdYQAWNgIAxDqfAIOioQBy7W0AOY16AIK4qQBrMlwARidbAAA07QDSAHcA/PRVAAFZTQDgcYAAAAAAAAAAAAAAAABA+yH5PwAAAAAtRHQ+AAAAgJhG+DwAAABgUcx4OwAAAICDG/A5AAAAQCAlejgAAACAIoLjNgAAAAAd82k1AAAAAAAA4D8AAAAAAADgvwAAAAAAAPA/AAAAAAAA+D8AAAAAAAAAAAbQz0Pr/Uw+AAAAAAAAAAAAAABAA7jiPwDsBwRuYW1lAcUBGgARX193YXNtX2NhbGxfY3RvcnMBBGFjb3MCBWFjb3NoAwRhc2luBAVhc2luaAUEYXRhbgYFYXRhbmgHBV9fY29zCBBfX3JlbV9waW8yX2xhcmdlCQpfX3JlbV9waW8yCgVfX3NpbgsDY29zDAdfX2V4cG8yDQRjb3NoDgNleHAPBWV4cG0xEANsb2cRBWxvZzFwEgNwb3cTBnNjYWxibhQDc2luFQRzaW5oFgVfX3RhbhcDdGFuGAR0YW5oGQZtZW1zZXQCnAYaAAABBQACcDABAmwwAgJsMQMCbDIEAmwzAgIAAnAwAQJsMAMGAAJwMAECbDACAmwxAwJsMgQCbDMFAmw0BAUAAnAwAQJsMAICbDEDAmwyBAJsMwUIAAJwMAECbDACAmwxAwJsMgQCbDMFAmw0BgJsNQcCbDYGBQACcDABAmwwAgJsMQMCbDIEAmwzBwUAAnAwAQJwMQICbDADAmwxBAJsMggdAAJwMAECcDECAnAyAwJwMwQCcDQFAmwwBgJsMQcCbDIIAmwzCQJsNAoCbDULAmw2DAJsNw0CbDgOAmw5DwNsMTAQA2wxMREDbDEyEgNsMTMTA2wxNBQDbDE1FQNsMTYWA2wxNxcDbDE4GANsMTkZA2wyMBoDbDIxGwNsMjIcA2wyMwkMAAJwMAECcDECAmwwAwJsMQQCbDIFAmwzBgJsNAcCbDUIAmw2CQJsNwoCbDgLAmw5CgYAAnAwAQJwMQICcDIDAmwwBAJsMQUCbDILBAACcDABAmwwAgJsMQMCbDIMAQACcDANBAACcDABAmwwAgJsMQMCbDIOCAACcDABAmwwAgJsMQMCbDIEAmwzBQJsNAYCbDUHAmw2DwkAAnAwAQJsMAICbDEDAmwyBAJsMwUCbDQGAmw1BwJsNggCbDcQBwACcDABAmwwAgJsMQMCbDIEAmwzBQJsNAYCbDURBwACcDABAmwwAgJsMQMCbDIEAmwzBQJsNAYCbDUSFQACcDABAnAxAgJsMAMCbDEEAmwyBQJsMwYCbDQHAmw1CAJsNgkCbDcKAmw4CwJsOQwDbDEwDQNsMTEOA2wxMg8DbDEzEANsMTQRA2wxNRIDbDE2EwNsMTcUA2wxOBMDAAJwMAECcDECAmwwFAQAAnAwAQJsMAICbDEDAmwyFQUAAnAwAQJsMAICbDEDAmwyBAJsMxYJAAJwMAECcDECAnAyAwJsMAQCbDEFAmwyBgJsMwcCbDQIAmw1FwMAAnAwAQJsMAICbDEYBQACcDABAmwwAgJsMQMCbDIEAmwzGQcAAnAwAQJwMQICcDIDAmwwBAJsMQUCbDIGAmwz" diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt deleted file mode 100644 index acb26f918..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("UNUSED_PARAMETER") - -package space.kscience.kmath.wasm - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.ast.evaluateConstants -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.wasm.internal.DoubleWasmBuilder -import space.kscience.kmath.wasm.internal.IntWasmBuilder - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: IntRing): IntExpression { - val typed = evaluateConstants(algebra) - - return if (typed is TypedMst.Constant) object : IntExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: IntArray): Int = typed.value - } else - IntWasmBuilder(typed).instance -} - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: IntRing, arguments: Map): Int = - compileToExpression(algebra)(arguments) - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: IntRing, vararg arguments: Pair): Int = - compileToExpression(algebra)(*arguments) - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: DoubleField): Expression { - val typed = evaluateConstants(algebra) - - return if (typed is TypedMst.Constant) object : DoubleExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: DoubleArray): Double = typed.value - } else - DoubleWasmBuilder(typed).instance -} - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: DoubleField, arguments: Map): Double = - compileToExpression(algebra)(arguments) - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = - compileToExpression(algebra)(*arguments) diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt deleted file mode 100644 index 7c397d5a0..000000000 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.ast - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import space.kscience.kmath.estree.compile as estreeCompile -import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression -import space.kscience.kmath.wasm.compile as wasmCompile -import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression - -private object WasmCompilerTestContext : CompilerTestContext { - override fun MST.compileToExpression(algebra: IntRing): Expression = wasmCompileToExpression(algebra) - override fun MST.compile(algebra: IntRing, arguments: Map): Int = wasmCompile(algebra, arguments) - override fun MST.compileToExpression(algebra: DoubleField): Expression = wasmCompileToExpression(algebra) - - override fun MST.compile(algebra: DoubleField, arguments: Map): Double = - wasmCompile(algebra, arguments) -} - -private object ESTreeCompilerTestContext : CompilerTestContext { - override fun MST.compileToExpression(algebra: IntRing): Expression = estreeCompileToExpression(algebra) - override fun MST.compile(algebra: IntRing, arguments: Map): Int = estreeCompile(algebra, arguments) - override fun MST.compileToExpression(algebra: DoubleField): Expression = estreeCompileToExpression(algebra) - - override fun MST.compile(algebra: DoubleField, arguments: Map): Double = - estreeCompile(algebra, arguments) -} - -internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { - contract { callsInPlace(action, InvocationKind.AT_LEAST_ONCE) } - action(WasmCompilerTestContext) - action(ESTreeCompilerTestContext) -} diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt new file mode 100644 index 000000000..5823518ce --- /dev/null +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.estree + +import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.complex.toComplex +import space.kscience.kmath.expressions.* +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.operations.ByteRing +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class TestESTreeConsistencyWithInterpreter { + + @Test + fun mstSpace() { + + val mst = MstGroup { + binaryOperationFunction("+")( + unaryOperationFunction("+")( + number(3.toByte()) - (number(2.toByte()) + (scale( + add(number(1), number(1)), + 2.0 + ) + number(1.toByte()) * 3.toByte() - number(1.toByte()))) + ), + + number(1) + ) + bindSymbol("x") + zero + } + + assertEquals( + mst.interpret(MstGroup, Symbol.x to MST.Numeric(2)), + mst.compile(MstGroup, Symbol.x to MST.Numeric(2)) + ) + } + + @Test + fun byteRing() { + val mst = MstRing { + binaryOperationFunction("+")( + unaryOperationFunction("+")( + (bindSymbol("x") - (2.toByte() + (scale( + add(number(1), number(1)), + 2.0 + ) + 1.toByte()))) * 3.0 - 1.toByte() + ), + + number(1) + ) * number(2) + } + + assertEquals( + mst.interpret(ByteRing, Symbol.x to 3.toByte()), + mst.compile(ByteRing, Symbol.x to 3.toByte()) + ) + } + + @Test + fun realField() { + val mst = MstField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( + (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + } + + assertEquals( + mst.interpret(DoubleField, Symbol.x to 2.0), + mst.compile(DoubleField, Symbol.x to 2.0) + ) + } + + @Test + fun complexField() { + val mst = MstField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( + (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + } + + assertEquals( + mst.interpret(ComplexField, Symbol.x to 2.0.toComplex()), + mst.compile(ComplexField, Symbol.x to 2.0.toComplex()) + ) + } +} diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeOperationsSupport.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeOperationsSupport.kt new file mode 100644 index 000000000..a1bff92d0 --- /dev/null +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeOperationsSupport.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.estree + +import space.kscience.kmath.expressions.MstExtendedField +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class TestESTreeOperationsSupport { + @Test + fun testUnaryOperationInvocation() { + val expression = MstExtendedField { -bindSymbol("x") }.compileToExpression(DoubleField) + val res = expression("x" to 2.0) + assertEquals(-2.0, res) + } + + @Test + fun testBinaryOperationInvocation() { + val expression = MstExtendedField { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField) + val res = expression("x" to 2.0) + assertEquals(-1.0, res) + } + + @Test + fun testConstProductInvocation() { + val res = MstExtendedField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0) + assertEquals(4.0, res) + } + + @Test + fun testMultipleCalls() { + val e = + MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) } + .compileToExpression(DoubleField) + val r = Random(0) + var s = 0.0 + repeat(1000000) { s += e("x" to r.nextDouble()) } + println(s) + } +} diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeSpecialization.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeSpecialization.kt new file mode 100644 index 000000000..b5ae1ca3f --- /dev/null +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeSpecialization.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.estree + +import space.kscience.kmath.expressions.MstExtendedField +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class TestESTreeSpecialization { + @Test + fun testUnaryPlus() { + val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField) + assertEquals(2.0, expr("x" to 2.0)) + } + + @Test + fun testUnaryMinus() { + val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField) + assertEquals(-2.0, expr("x" to 2.0)) + } + + @Test + fun testAdd() { + val expr = MstExtendedField { + binaryOperationFunction("+")(bindSymbol("x"), + bindSymbol("x")) + }.compileToExpression(DoubleField) + assertEquals(4.0, expr("x" to 2.0)) + } + + @Test + fun testSine() { + val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField) + assertEquals(0.0, expr("x" to 0.0)) + } + + @Test + fun testMinus() { + val expr = MstExtendedField { + binaryOperationFunction("-")(bindSymbol("x"), + bindSymbol("x")) + }.compileToExpression(DoubleField) + assertEquals(0.0, expr("x" to 2.0)) + } + + @Test + fun testDivide() { + val expr = MstExtendedField { + binaryOperationFunction("/")(bindSymbol("x"), + bindSymbol("x")) + }.compileToExpression(DoubleField) + assertEquals(1.0, expr("x" to 2.0)) + } + + @Test + fun testPower() { + val expr = MstExtendedField { + binaryOperationFunction("pow")(bindSymbol("x"), number(2)) + }.compileToExpression(DoubleField) + + assertEquals(4.0, expr("x" to 2.0)) + } +} diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeVariables.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeVariables.kt new file mode 100644 index 000000000..1effe14e1 --- /dev/null +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeVariables.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.estree + +import space.kscience.kmath.expressions.MstRing +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.operations.ByteRing +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +internal class TestESTreeVariables { + @Test + fun testVariable() { + val expr = MstRing{ bindSymbol("x") }.compileToExpression(ByteRing) + assertEquals(1.toByte(), expr("x" to 1.toByte())) + } + + @Test + fun testUndefinedVariableFails() { + val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing) + assertFailsWith { expr() } + } +} diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt deleted file mode 100644 index 132f9f1bd..000000000 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.wasm - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.MstExtendedField -import space.kscience.kmath.expressions.MstRing -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.invoke -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -internal class TestWasmSpecific { - @Test - fun int() { - val res = MstRing { number(100000000) + number(10000000) }.compile(IntRing) - assertEquals(110000000, res) - } - - @Test - fun real() { - val res = MstExtendedField { number(100000000) + number(2).pow(10) }.compile(DoubleField) - assertEquals(100001024.0, res) - } - - @Test - fun argsPassing() { - val res = MstExtendedField { y + x.pow(10) }.compile( - DoubleField, - x to 2.0, - y to 100000000.0, - ) - - assertEquals(100001024.0, res) - } - - @Test - fun powFunction() { - val expr = MstExtendedField { x.pow(1.0 / 6.0) }.compileToExpression(DoubleField) - assertEquals(0.9730585187140817, expr(x to 0.8488554755054833)) - } - - private companion object { - private val x by symbol - private val y by symbol - } -} diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt index 7094d0442..dbce893d1 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt @@ -1,21 +1,19 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("UNUSED_PARAMETER") - package space.kscience.kmath.asm -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.asm.internal.* -import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.ast.evaluateConstants -import space.kscience.kmath.expressions.* +import space.kscience.kmath.asm.internal.AsmBuilder +import space.kscience.kmath.asm.internal.buildName +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.MST.* +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.misc.Symbol import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.LongRing +import space.kscience.kmath.operations.NumericAlgebra /** * Compiles given MST to an Expression using AST compiler. @@ -25,171 +23,73 @@ import space.kscience.kmath.operations.LongRing * @return the compiled expression. * @author Alexander Nozik */ -@OptIn(UnstableKMathAPI::class) @PublishedApi internal fun MST.compileWith(type: Class, algebra: Algebra): Expression { - val typed = evaluateConstants(algebra) - if (typed is TypedMst.Constant) return Expression { typed.value } + fun AsmBuilder.visit(node: MST): Unit = when (node) { + is Symbolic -> { + val symbol = algebra.bindSymbolOrNull(node.value) - fun GenericAsmBuilder.variablesVisitor(node: TypedMst): Unit = when (node) { - is TypedMst.Unary -> variablesVisitor(node.value) - - is TypedMst.Binary -> { - variablesVisitor(node.left) - variablesVisitor(node.right) + if (symbol != null) + loadObjectConstant(symbol as Any) + else + loadVariable(node.value) } - is TypedMst.Variable -> prepareVariable(node.symbol) - is TypedMst.Constant -> Unit - } + is Numeric -> loadNumberConstant(node.value) - fun GenericAsmBuilder.expressionVisitor(node: TypedMst): Unit = when (node) { - is TypedMst.Constant -> if (node.number != null) - loadNumberConstant(node.number) - else - loadObjectConstant(node.value) + is Unary -> when { + algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant( + algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) - is TypedMst.Variable -> loadVariable(node.symbol) - is TypedMst.Unary -> buildCall(node.function) { expressionVisitor(node.value) } + else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) } + } - is TypedMst.Binary -> buildCall(node.function) { - expressionVisitor(node.left) - expressionVisitor(node.right) + is Binary -> when { + algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant( + algebra.binaryOperationFunction(node.operation).invoke( + algebra.number((node.left as Numeric).value), + algebra.number((node.right as Numeric).value) + ) + ) + + algebra is NumericAlgebra && node.left is Numeric -> buildCall( + algebra.leftSideNumberOperationFunction(node.operation)) { + visit(node.left) + visit(node.right) + } + + algebra is NumericAlgebra && node.right is Numeric -> buildCall( + algebra.rightSideNumberOperationFunction(node.operation)) { + visit(node.left) + visit(node.right) + } + + else -> buildCall(algebra.binaryOperationFunction(node.operation)) { + visit(node.left) + visit(node.right) + } } } - return GenericAsmBuilder( - type, - buildName("${typed.hashCode()}_${type.simpleName}"), - { variablesVisitor(typed) }, - { expressionVisitor(typed) }, - ).instance + return AsmBuilder(type, buildName(this)) { visit(this@compileWith) }.instance } + /** * Create a compiled expression with given [MST] and given [algebra]. */ public inline fun MST.compileToExpression(algebra: Algebra): Expression = compileWith(T::class.java, algebra) + /** * Compile given MST to expression and evaluate it against [arguments] */ public inline fun MST.compile(algebra: Algebra, arguments: Map): T = - compileToExpression(algebra)(arguments) + compileToExpression(algebra).invoke(arguments) /** * Compile given MST to expression and evaluate it against [arguments] */ public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = - compileToExpression(algebra)(*arguments) - - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: IntRing): IntExpression { - val typed = evaluateConstants(algebra) - - return if (typed is TypedMst.Constant) object : IntExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: IntArray): Int = typed.value - } else - IntAsmBuilder(typed).instance -} - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: IntRing, arguments: Map): Int = - compileToExpression(algebra)(arguments) - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: IntRing, vararg arguments: Pair): Int = - compileToExpression(algebra)(*arguments) - - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: LongRing): LongExpression { - val typed = evaluateConstants(algebra) - - return if (typed is TypedMst.Constant) object : LongExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: LongArray): Long = typed.value - } else - LongAsmBuilder(typed).instance -} - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: LongRing, arguments: Map): Long = - compileToExpression(algebra)(arguments) - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: LongRing, vararg arguments: Pair): Long = - compileToExpression(algebra)(*arguments) - - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: DoubleField): DoubleExpression { - val typed = evaluateConstants(algebra) - - return if (typed is TypedMst.Constant) object : DoubleExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: DoubleArray): Double = typed.value - } else - DoubleAsmBuilder(typed).instance -} - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: DoubleField, arguments: Map): Double = - compileToExpression(algebra)(arguments) - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = - compileToExpression(algebra)(*arguments) + compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index e1fd455fd..bdd8f52b6 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -1,55 +1,349 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.asm.internal -import org.objectweb.asm.Type -import org.objectweb.asm.Type.getObjectType +import org.objectweb.asm.* +import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.Type.* +import org.objectweb.asm.commons.InstructionAdapter +import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.MST +import java.lang.invoke.MethodHandles +import java.lang.invoke.MethodType +import java.util.stream.Collectors.toMap +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract -internal abstract class AsmBuilder { +/** + * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. + * This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class. + * + * @property T the type of AsmExpression to unwrap. + * @property className the unique class name of new loaded class. + * @property callbackAtInvokeL0 the function to apply to this object when generating invoke method, label 0. + * @author Iaroslav Postovalov + */ +internal class AsmBuilder( + classOfT: Class<*>, + private val className: String, + private val callbackAtInvokeL0: AsmBuilder.() -> Unit, +) { /** - * Internal classloader with alias to define class from byte array. + * Internal classloader of [AsmBuilder] with alias to define class from byte array. */ - class ByteArrayClassLoader(parent: ClassLoader) : ClassLoader(parent) { + private class ClassLoader(parent: java.lang.ClassLoader) : java.lang.ClassLoader(parent) { fun defineClass(name: String?, b: ByteArray): Class<*> = defineClass(name, b, 0, b.size) } - protected val classLoader = ByteArrayClassLoader(javaClass.classLoader) + /** + * The instance of [ClassLoader] used by this builder. + */ + private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader) + + /** + * ASM type for [T]. + */ + private val tType: Type = classOfT.asm + + /** + * ASM type for new class. + */ + private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) + + /** + * List of constants to provide to the subclass. + */ + private val constants: MutableList = mutableListOf() + + /** + * Method visitor of `invoke` method of the subclass. + */ + private lateinit var invokeMethodVisitor: InstructionAdapter + + /** + * Subclasses, loads and instantiates [Expression] for given parameters. + * + * The built instance is cached. + */ + @Suppress("UNCHECKED_CAST") + val instance: Expression by lazy { + val hasConstants: Boolean + + val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { + visit( + V1_8, + ACC_PUBLIC or ACC_FINAL or ACC_SUPER, + classType.internalName, + "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", + OBJECT_TYPE.internalName, + arrayOf(EXPRESSION_TYPE.internalName), + ) + + visitMethod( + ACC_PUBLIC or ACC_FINAL, + "invoke", + getMethodDescriptor(tType, MAP_TYPE), + "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", + null, + ).instructionAdapter { + invokeMethodVisitor = this + visitCode() + val l0 = label() + callbackAtInvokeL0() + areturn(tType) + val l1 = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + l0, + l1, + 0, + ) + + visitLocalVariable( + "arguments", + MAP_TYPE.descriptor, + "L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;", + l0, + l1, + 1, + ) + + visitMaxs(0, 2) + visitEnd() + } + + visitMethod( + ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, + "invoke", + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), + null, + null, + ).instructionAdapter { + visitCode() + val l0 = label() + load(0, OBJECT_TYPE) + load(1, MAP_TYPE) + invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) + areturn(tType) + val l1 = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + l0, + l1, + 0, + ) + + visitMaxs(0, 2) + visitEnd() + } + + hasConstants = constants.isNotEmpty() + + if (hasConstants) + visitField( + access = ACC_PRIVATE or ACC_FINAL, + name = "constants", + descriptor = OBJECT_ARRAY_TYPE.descriptor, + signature = null, + value = null, + block = FieldVisitor::visitEnd, + ) + + visitMethod( + ACC_PUBLIC, + "", + getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), + null, + null, + ).instructionAdapter { + val l0 = label() + load(0, classType) + invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) + label() + load(0, classType) + + if (hasConstants) { + label() + load(0, classType) + load(1, OBJECT_ARRAY_TYPE) + putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) + } + + label() + visitInsn(RETURN) + val l4 = label() + visitLocalVariable("this", classType.descriptor, null, l0, l4, 0) + + if (hasConstants) + visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, 1) + + visitMaxs(0, 3) + visitEnd() + } + + visitEnd() + } + + val cls = classLoader.defineClass(className, classWriter.toByteArray()) + // java.io.File("dump.class").writeBytes(classWriter.toByteArray()) + val l = MethodHandles.publicLookup() + + if (hasConstants) + l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java)) + .invoke(constants.toTypedArray()) as Expression + else + l.findConstructor(cls, MethodType.methodType(Void.TYPE)).invoke() as Expression + } + + /** + * Loads [java.lang.Object] constant from constants. + */ + fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { + val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex + invokeMethodVisitor.load(0, classType) + getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) + iconst(idx) + visitInsn(AALOAD) + if (type != OBJECT_TYPE) checkcast(type) + } + + /** + * Either loads a numeric constant [value] from the class's constants field or boxes a primitive + * constant from the constant pool. + */ + fun loadNumberConstant(value: Number) { + val boxed = value.javaClass.asm + val primitive = BOXED_TO_PRIMITIVES[boxed] + + if (primitive != null) { + when (primitive) { + BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) + FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) + LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) + INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + } + + val r = PRIMITIVES_TO_BOXED.getValue(primitive) + + invokeMethodVisitor.invokestatic( + r.internalName, + "valueOf", + getMethodDescriptor(r, primitive), + false, + ) + + return + } + + loadObjectConstant(value, boxed) + } + + /** + * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. + */ + fun loadVariable(name: String): Unit = invokeMethodVisitor.run { + load(1, MAP_TYPE) + aconst(name) + + invokestatic( + MAP_INTRINSICS_TYPE.internalName, + "getOrFail", + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), + false, + ) + + checkcast(tType) + } + + inline fun buildCall(function: Function, parameters: AsmBuilder.() -> Unit) { + contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } + val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces } + + val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount + ?: error("Provided function object doesn't contain invoke method") + + val type = getType(`interface`) + loadObjectConstant(function, type) + parameters(this) + + invokeMethodVisitor.invokeinterface( + type.internalName, + "invoke", + getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE }), + ) + + invokeMethodVisitor.checkcast(tType) + } + + companion object { + /** + * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. + */ + private val BOXED_TO_PRIMITIVES: Map by lazy { + hashMapOf( + Byte::class.java.asm to BYTE_TYPE, + Short::class.java.asm to SHORT_TYPE, + Integer::class.java.asm to INT_TYPE, + Long::class.java.asm to LONG_TYPE, + Float::class.java.asm to FLOAT_TYPE, + Double::class.java.asm to DOUBLE_TYPE, + ) + } + + /** + * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. + */ + private val PRIMITIVES_TO_BOXED: Map by lazy { + BOXED_TO_PRIMITIVES.entries.stream().collect( + toMap(Map.Entry::value, Map.Entry::key), + ) + } - protected companion object { /** * ASM type for [Expression]. */ - val EXPRESSION_TYPE: Type = getObjectType("space/kscience/kmath/expressions/Expression") + val EXPRESSION_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Expression") } /** * ASM type for [java.util.Map]. */ - val MAP_TYPE: Type = getObjectType("java/util/Map") + val MAP_TYPE: Type by lazy { getObjectType("java/util/Map") } /** * ASM type for [java.lang.Object]. */ - val OBJECT_TYPE: Type = getObjectType("java/lang/Object") + val OBJECT_TYPE: Type by lazy { getObjectType("java/lang/Object") } + + /** + * ASM type for array of [java.lang.Object]. + */ + val OBJECT_ARRAY_TYPE: Type by lazy { getType("[Ljava/lang/Object;") } /** * ASM type for [java.lang.String]. */ - val STRING_TYPE: Type = getObjectType("java/lang/String") + val STRING_TYPE: Type by lazy { getObjectType("java/lang/String") } /** * ASM type for MapIntrinsics. */ - val MAP_INTRINSICS_TYPE: Type = getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") + val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") } /** - * ASM Type for [space.kscience.kmath.expressions.Symbol]. + * ASM Type for [kscience.kmath.expressions.Symbol]. */ - val SYMBOL_TYPE: Type = getObjectType("space/kscience/kmath/expressions/Symbol") - - const val ARGUMENTS_NAME = "args" + val SYMBOL_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Symbol") } } } diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt deleted file mode 100644 index acae45d87..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.asm.internal - -import org.objectweb.asm.* -import org.objectweb.asm.Opcodes.* -import org.objectweb.asm.Type.* -import org.objectweb.asm.commons.InstructionAdapter -import space.kscience.kmath.expressions.* -import java.lang.invoke.MethodHandles -import java.lang.invoke.MethodType -import java.nio.file.Paths -import java.util.stream.Collectors.toMap -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.io.path.writeBytes - -/** - * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. - * This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class. - * - * @property T the type of AsmExpression to unwrap. - * @property className the unique class name of new loaded class. - * @property expressionResultCallback the function to apply to this object when generating expression value. - * @author Iaroslav Postovalov - */ -internal class GenericAsmBuilder( - classOfT: Class<*>, - private val className: String, - private val variablesPrepareCallback: GenericAsmBuilder.() -> Unit, - private val expressionResultCallback: GenericAsmBuilder.() -> Unit, -) : AsmBuilder() { - /** - * ASM type for [T]. - */ - private val tType: Type = classOfT.asm - - /** - * ASM type for new class. - */ - private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) - - /** - * List of constants to provide to the subclass. - */ - private val constants = mutableListOf() - - /** - * Method visitor of `invoke` method of the subclass. - */ - private lateinit var invokeMethodVisitor: InstructionAdapter - - /** - * Local variables indices are indices of symbols in this list. - */ - private val argumentsLocals = mutableListOf() - - /** - * Subclasses, loads and instantiates [Expression] for given parameters. - * - * The built instance is cached. - */ - @Suppress("UNCHECKED_CAST", "UNUSED_VARIABLE") - val instance: Expression by lazy { - val hasConstants: Boolean - - val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { - visit( - V1_8, - ACC_PUBLIC or ACC_FINAL or ACC_SUPER, - classType.internalName, - "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", - OBJECT_TYPE.internalName, - arrayOf(EXPRESSION_TYPE.internalName), - ) - - visitMethod( - ACC_PUBLIC, - "invoke", - getMethodDescriptor(tType, MAP_TYPE), - "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", - null, - ).instructionAdapter { - invokeMethodVisitor = this - visitCode() - val preparingVariables = label() - variablesPrepareCallback() - val expressionResult = label() - expressionResultCallback() - areturn(tType) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - preparingVariables, - end, - 0, - ) - - visitLocalVariable( - "arguments", - MAP_TYPE.descriptor, - "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", - preparingVariables, - end, - 1, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_BRIDGE or ACC_SYNTHETIC, - "invoke", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), - null, - null, - ).instructionAdapter { - visitCode() - val start = label() - load(0, OBJECT_TYPE) - load(1, MAP_TYPE) - invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) - areturn(tType) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitMaxs(0, 0) - visitEnd() - } - - hasConstants = constants.isNotEmpty() - - if (hasConstants) - visitField( - access = ACC_PRIVATE or ACC_FINAL, - name = "constants", - descriptor = OBJECT_ARRAY_TYPE.descriptor, - signature = null, - value = null, - block = FieldVisitor::visitEnd, - ) - - visitMethod( - ACC_PUBLIC or ACC_SYNTHETIC, - "", - getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), - null, - null, - ).instructionAdapter { - val l0 = label() - load(0, classType) - invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) - label() - load(0, classType) - - if (hasConstants) { - label() - load(0, classType) - load(1, OBJECT_ARRAY_TYPE) - putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) - } - - label() - areturn(VOID_TYPE) - val l4 = label() - visitLocalVariable("this", classType.descriptor, null, l0, l4, 0) - - if (hasConstants) - visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, 1) - - visitMaxs(0, 0) - visitEnd() - } - - visitEnd() - } - - val binary = classWriter.toByteArray() - val cls = classLoader.defineClass(className, binary) - - if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") - Paths.get("${className.split('.').last()}.class").writeBytes(binary) - - val l = MethodHandles.publicLookup() - - (if (hasConstants) - l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java))(constants.toTypedArray()) - else - l.findConstructor(cls, MethodType.methodType(Void.TYPE))()) as Expression - } - - /** - * Loads [java.lang.Object] constant from constants. - */ - fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { - val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex - load(0, classType) - getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) - iconst(idx) - aload(OBJECT_TYPE) - if (type != OBJECT_TYPE) checkcast(type) - } - - /** - * Either loads a numeric constant [value] from the class's constants field or boxes a primitive - * constant from the constant pool. - */ - fun loadNumberConstant(value: Number) { - val boxed = value.javaClass.asm - val primitive = BOXED_TO_PRIMITIVES[boxed] - - if (primitive != null) { - when (primitive) { - BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) - FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) - LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) - INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - } - - val r = boxed - - invokeMethodVisitor.invokestatic( - r.internalName, - "valueOf", - getMethodDescriptor(r, primitive), - false, - ) - - return - } - - loadObjectConstant(value, boxed) - } - - /** - * Stores value variable [name] into a local. Should be called within [variablesPrepareCallback] before using - * [loadVariable]. - */ - fun prepareVariable(name: Symbol): Unit = invokeMethodVisitor.run { - if (name in argumentsLocals) return@run - load(1, MAP_TYPE) - aconst(name.identity) - - invokestatic( - MAP_INTRINSICS_TYPE.internalName, - "getOrFail", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), - false, - ) - - checkcast(tType) - var idx = argumentsLocals.indexOf(name) - - if (idx == -1) { - argumentsLocals += name - idx = argumentsLocals.lastIndex - } - - store(2 + idx, tType) - } - - /** - * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored - * with [prepareVariable] first. - */ - fun loadVariable(name: Symbol): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tType) - - inline fun buildCall(function: Function, parameters: GenericAsmBuilder.() -> Unit) { - contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } - val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces } - - val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount - ?: error("Provided function object doesn't contain invoke method") - - val type = getType(`interface`) - loadObjectConstant(function, type) - parameters(this) - - invokeMethodVisitor.invokeinterface( - type.internalName, - "invoke", - getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE }), - ) - - invokeMethodVisitor.checkcast(tType) - } - - private companion object { - /** - * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. - */ - private val BOXED_TO_PRIMITIVES: Map by lazy { - hashMapOf( - Byte::class.java.asm to BYTE_TYPE, - Short::class.java.asm to SHORT_TYPE, - Integer::class.java.asm to INT_TYPE, - Long::class.java.asm to LONG_TYPE, - Float::class.java.asm to FLOAT_TYPE, - Double::class.java.asm to DOUBLE_TYPE, - ) - } - - /** - * ASM type for array of [java.lang.Object]. - */ - val OBJECT_ARRAY_TYPE: Type = getType("[Ljava/lang/Object;") - } -} diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt deleted file mode 100644 index a3e5b7522..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.asm.internal - -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.FieldVisitor -import org.objectweb.asm.Opcodes.* -import org.objectweb.asm.Type -import org.objectweb.asm.Type.* -import org.objectweb.asm.commons.InstructionAdapter -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.* -import java.lang.invoke.MethodHandles -import java.lang.invoke.MethodType -import java.nio.file.Paths -import kotlin.io.path.writeBytes - -@UnstableKMathAPI -internal sealed class PrimitiveAsmBuilder>( - protected val algebra: NumericAlgebra, - classOfT: Class<*>, - protected val classOfTPrimitive: Class<*>, - expressionParent: Class, - protected val target: TypedMst, -) : AsmBuilder() { - private val className: String = buildName("${target.hashCode()}_${classOfT.simpleName}") - - /** - * ASM type for [tType]. - */ - private val tType: Type = classOfT.asm - - /** - * ASM type for [classOfTPrimitive]. - */ - protected val tTypePrimitive: Type = classOfTPrimitive.asm - - /** - * ASM type for array of [classOfTPrimitive]. - */ - protected val tTypePrimitiveArray: Type = getType("[" + classOfTPrimitive.asm.descriptor) - - /** - * ASM type for expression parent. - */ - private val expressionParentType = expressionParent.asm - - /** - * ASM type for new class. - */ - private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) - - /** - * Method visitor of `invoke` method of the subclass. - */ - protected lateinit var invokeMethodVisitor: InstructionAdapter - - /** - * Indexer for arguments in [target]. - */ - private val argumentsIndexer = mutableListOf() - - /** - * Subclasses, loads and instantiates [Expression] for given parameters. - * - * The built instance is cached. - */ - @Suppress("UNCHECKED_CAST") - val instance: E by lazy { - val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { - visit( - V1_8, - ACC_PUBLIC or ACC_FINAL or ACC_SUPER, - classType.internalName, - "${OBJECT_TYPE.descriptor}${expressionParentType.descriptor}", - OBJECT_TYPE.internalName, - arrayOf(expressionParentType.internalName), - ) - - visitField( - access = ACC_PRIVATE or ACC_FINAL, - name = "indexer", - descriptor = SYMBOL_INDEXER_TYPE.descriptor, - signature = null, - value = null, - block = FieldVisitor::visitEnd, - ) - visitMethod( - ACC_PUBLIC, - "getIndexer", - getMethodDescriptor(SYMBOL_INDEXER_TYPE), - null, - null, - ).instructionAdapter { - visitCode() - val start = label() - load(0, classType) - getfield(classType.internalName, "indexer", SYMBOL_INDEXER_TYPE.descriptor) - areturn(SYMBOL_INDEXER_TYPE) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC, - "invoke", - getMethodDescriptor(tTypePrimitive, tTypePrimitiveArray), - null, - null, - ).instructionAdapter { - invokeMethodVisitor = this - visitCode() - val start = label() - visitVariables(target, arrayMode = true) - visitExpression(target) - areturn(tTypePrimitive) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitLocalVariable( - "arguments", - tTypePrimitiveArray.descriptor, - null, - start, - end, - 1, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_FINAL, - "invoke", - getMethodDescriptor(tType, MAP_TYPE), - "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", - null, - ).instructionAdapter { - invokeMethodVisitor = this - visitCode() - val start = label() - visitVariables(target, arrayMode = false) - visitExpression(target) - box() - areturn(tType) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitLocalVariable( - "arguments", - MAP_TYPE.descriptor, - "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", - start, - end, - 1, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, - "invoke", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), - null, - null, - ).instructionAdapter { - visitCode() - val start = label() - load(0, OBJECT_TYPE) - load(1, MAP_TYPE) - invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) - areturn(tType) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_SYNTHETIC, - "", - getMethodDescriptor(VOID_TYPE, SYMBOL_INDEXER_TYPE), - null, - null, - ).instructionAdapter { - val start = label() - load(0, classType) - invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) - load(0, classType) - load(1, SYMBOL_INDEXER_TYPE) - putfield(classType.internalName, "indexer", SYMBOL_INDEXER_TYPE.descriptor) - areturn(VOID_TYPE) - val end = label() - visitLocalVariable("this", classType.descriptor, null, start, end, 0) - visitLocalVariable("indexer", SYMBOL_INDEXER_TYPE.descriptor, null, start, end, 1) - visitMaxs(0, 0) - visitEnd() - } - - visitEnd() - } - - val binary = classWriter.toByteArray() - val cls = classLoader.defineClass(className, binary) - - if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") - Paths.get("${className.split('.').last()}.class").writeBytes(binary) - - MethodHandles - .publicLookup() - .findConstructor(cls, MethodType.methodType(Void.TYPE, SymbolIndexer::class.java)) - .invoke(SimpleSymbolIndexer(argumentsIndexer)) as E - } - - /** - * Loads a numeric constant [value] from the class's constants. - */ - protected fun loadNumberConstant(value: Number) { - when (tTypePrimitive) { - BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) - FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) - LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) - INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - } - } - - /** - * Stores value variable [name] into a local. Should be called before using [loadVariable]. Should be called only - * once for a variable. - */ - protected fun prepareVariable(name: Symbol, arrayMode: Boolean): Unit = invokeMethodVisitor.run { - var argumentIndex = argumentsIndexer.indexOf(name) - - if (argumentIndex == -1) { - argumentsIndexer += name - argumentIndex = argumentsIndexer.lastIndex - } - - val localIndex = 2 + argumentIndex * tTypePrimitive.size - - if (arrayMode) { - load(1, tTypePrimitiveArray) - iconst(argumentIndex) - aload(tTypePrimitive) - store(localIndex, tTypePrimitive) - } else { - load(1, MAP_TYPE) - aconst(name.identity) - - invokestatic( - MAP_INTRINSICS_TYPE.internalName, - "getOrFail", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), - false, - ) - - checkcast(tType) - unbox() - store(localIndex, tTypePrimitive) - } - } - - /** - * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored - * with [prepareVariable] first. - */ - protected fun loadVariable(name: Symbol) { - val argumentIndex = argumentsIndexer.indexOf(name) - val localIndex = 2 + argumentIndex * tTypePrimitive.size - invokeMethodVisitor.load(localIndex, tTypePrimitive) - } - - private fun unbox() = invokeMethodVisitor.run { - invokevirtual( - NUMBER_TYPE.internalName, - "${classOfTPrimitive.simpleName}Value", - getMethodDescriptor(tTypePrimitive), - false - ) - } - - private fun box() = invokeMethodVisitor.run { - invokestatic(tType.internalName, "valueOf", getMethodDescriptor(tType, tTypePrimitive), false) - } - - private fun visitVariables( - node: TypedMst, - arrayMode: Boolean, - alreadyLoaded: MutableList = mutableListOf() - ): Unit = when (node) { - is TypedMst.Variable -> if (node.symbol !in alreadyLoaded) { - alreadyLoaded += node.symbol - prepareVariable(node.symbol, arrayMode) - } else Unit - - is TypedMst.Unary -> visitVariables(node.value, arrayMode, alreadyLoaded) - - is TypedMst.Binary -> { - visitVariables(node.left, arrayMode, alreadyLoaded) - visitVariables(node.right, arrayMode, alreadyLoaded) - } - - is TypedMst.Constant -> Unit - } - - private fun visitExpression(node: TypedMst): Unit = when (node) { - is TypedMst.Variable -> loadVariable(node.symbol) - - is TypedMst.Constant -> loadNumberConstant( - node.number ?: error("Object constants are not supported by pritimive ASM builder"), - ) - - is TypedMst.Unary -> visitUnary(node) - is TypedMst.Binary -> visitBinary(node) - } - - protected open fun visitUnary(node: TypedMst.Unary) = visitExpression(node.value) - - protected open fun visitBinary(node: TypedMst.Binary) { - visitExpression(node.left) - visitExpression(node.right) - } - - protected companion object { - /** - * ASM type for [java.lang.Number]. - */ - val NUMBER_TYPE: Type = getObjectType("java/lang/Number") - - /** - * ASM type for [SymbolIndexer]. - */ - val SYMBOL_INDEXER_TYPE: Type = getObjectType("space/kscience/kmath/expressions/SymbolIndexer") - } -} - -@UnstableKMathAPI -internal class DoubleAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder( - DoubleField, - java.lang.Double::class.java, - java.lang.Double.TYPE, - DoubleExpression::class.java, - target, -) { - private fun buildUnaryJavaMathCall(name: String) = invokeMethodVisitor.invokestatic( - MATH_TYPE.internalName, - name, - getMethodDescriptor(tTypePrimitive, tTypePrimitive), - false, - ) - - @Suppress("SameParameterValue") - private fun buildBinaryJavaMathCall(name: String) = invokeMethodVisitor.invokestatic( - MATH_TYPE.internalName, - name, - getMethodDescriptor(tTypePrimitive, tTypePrimitive, tTypePrimitive), - false, - ) - - private fun buildUnaryKotlinMathCall(name: String) = invokeMethodVisitor.invokestatic( - MATH_KT_TYPE.internalName, - name, - getMethodDescriptor(tTypePrimitive, tTypePrimitive), - false, - ) - - override fun visitUnary(node: TypedMst.Unary) { - super.visitUnary(node) - - when (node.operation) { - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(DNEG) - GroupOps.PLUS_OPERATION -> Unit - PowerOperations.SQRT_OPERATION -> buildUnaryJavaMathCall("sqrt") - TrigonometricOperations.SIN_OPERATION -> buildUnaryJavaMathCall("sin") - TrigonometricOperations.COS_OPERATION -> buildUnaryJavaMathCall("cos") - TrigonometricOperations.TAN_OPERATION -> buildUnaryJavaMathCall("tan") - TrigonometricOperations.ASIN_OPERATION -> buildUnaryJavaMathCall("asin") - TrigonometricOperations.ACOS_OPERATION -> buildUnaryJavaMathCall("acos") - TrigonometricOperations.ATAN_OPERATION -> buildUnaryJavaMathCall("atan") - ExponentialOperations.SINH_OPERATION -> buildUnaryJavaMathCall("sqrt") - ExponentialOperations.COSH_OPERATION -> buildUnaryJavaMathCall("cosh") - ExponentialOperations.TANH_OPERATION -> buildUnaryJavaMathCall("tanh") - ExponentialOperations.ASINH_OPERATION -> buildUnaryKotlinMathCall("asinh") - ExponentialOperations.ACOSH_OPERATION -> buildUnaryKotlinMathCall("acosh") - ExponentialOperations.ATANH_OPERATION -> buildUnaryKotlinMathCall("atanh") - ExponentialOperations.EXP_OPERATION -> buildUnaryJavaMathCall("exp") - ExponentialOperations.LN_OPERATION -> buildUnaryJavaMathCall("log") - else -> super.visitUnary(node) - } - } - - override fun visitBinary(node: TypedMst.Binary) { - super.visitBinary(node) - - when (node.operation) { - GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(DADD) - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(DSUB) - RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(DMUL) - FieldOps.DIV_OPERATION -> invokeMethodVisitor.visitInsn(DDIV) - PowerOperations.POW_OPERATION -> buildBinaryJavaMathCall("pow") - else -> super.visitBinary(node) - } - } - - private companion object { - val MATH_TYPE: Type = getObjectType("java/lang/Math") - val MATH_KT_TYPE: Type = getObjectType("kotlin/math/MathKt") - } -} - -@UnstableKMathAPI -internal class IntAsmBuilder(target: TypedMst) : - PrimitiveAsmBuilder( - IntRing, - Integer::class.java, - Integer.TYPE, - IntExpression::class.java, - target - ) { - override fun visitUnary(node: TypedMst.Unary) { - super.visitUnary(node) - - when (node.operation) { - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(INEG) - GroupOps.PLUS_OPERATION -> Unit - else -> super.visitUnary(node) - } - } - - override fun visitBinary(node: TypedMst.Binary) { - super.visitBinary(node) - - when (node.operation) { - GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(IADD) - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(ISUB) - RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(IMUL) - else -> super.visitBinary(node) - } - } -} - -@UnstableKMathAPI -internal class LongAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder( - LongRing, - java.lang.Long::class.java, - java.lang.Long.TYPE, - LongExpression::class.java, - target, -) { - override fun visitUnary(node: TypedMst.Unary) { - super.visitUnary(node) - - when (node.operation) { - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(LNEG) - GroupOps.PLUS_OPERATION -> Unit - else -> super.visitUnary(node) - } - } - - override fun visitBinary(node: TypedMst.Binary) { - super.visitBinary(node) - - when (node.operation) { - GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(LADD) - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(LSUB) - RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(LMUL) - else -> super.visitBinary(node) - } - } -} diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt index b3ccfdc0c..560780f99 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -52,18 +52,18 @@ internal inline fun MethodVisitor.instructionAdapter(block: InstructionAdapter.( * * @author Iaroslav Postovalov */ -internal fun MethodVisitor.label(): Label = Label().also(::visitLabel) +internal fun MethodVisitor.label(): Label = Label().also { visitLabel(it) } /** - * Creates a class name for [Expression] based with appending [marker] to reduce collisions. + * Creates a class name for [Expression] subclassed to implement [mst] provided. * - * These methods help to avoid collisions of class name to prevent loading several classes with the same name. If there + * This methods helps to avoid collisions of class name to prevent loading several classes with the same name. If there * is a colliding class, change [collision] parameter or leave it `0` to check existing classes recursively. * * @author Iaroslav Postovalov */ -internal tailrec fun buildName(marker: String, collision: Int = 0): String { - val name = "space.kscience.kmath.asm.generated.CompiledExpression_${marker}_$collision" +internal tailrec fun buildName(mst: MST, collision: Int = 0): String { + val name = "kscience.kmath.asm.generated.AsmCompiledExpression_${mst.hashCode()}_$collision" try { Class.forName(name) @@ -71,7 +71,7 @@ internal tailrec fun buildName(marker: String, collision: Int = 0): String { return name } - return buildName(marker, collision + 1) + return buildName(mst, collision + 1) } @Suppress("FunctionName") diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt index 6459f4dcf..dc8f19fb6 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,12 +7,12 @@ package space.kscience.kmath.asm.internal -import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.StringSymbol +import space.kscience.kmath.misc.Symbol /** * Gets value with given [key] or throws [NoSuchElementException] whenever it is not present. * * @author Iaroslav Postovalov */ -@Suppress("unused") -internal fun Map.getOrFail(key: String): V = getValue(Symbol(key)) +internal fun Map.getOrFail(key: String): V = getValue(StringSymbol(key)) diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt similarity index 75% rename from kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt rename to kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt index 2c9a2a9ad..025f4984c 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt @@ -1,8 +1,10 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +// TODO move to common when https://github.com/h0tk3y/better-parse/pull/37 is merged + package space.kscience.kmath.ast import com.github.h0tk3y.betterParse.combinators.* @@ -17,12 +19,10 @@ import com.github.h0tk3y.betterParse.lexer.regexToken import com.github.h0tk3y.betterParse.parser.ParseResult import com.github.h0tk3y.betterParse.parser.Parser import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.FieldOps -import space.kscience.kmath.operations.GroupOps +import space.kscience.kmath.operations.FieldOperations +import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.RingOps -import kotlin.math.floor +import space.kscience.kmath.operations.RingOperations /** * better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4. @@ -31,6 +31,7 @@ import kotlin.math.floor * @author Iaroslav Postovalov */ public object ArithmeticsEvaluator : Grammar() { + // TODO replace with "...".toRegex() when better-parse 0.4.1 is released private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?".toRegex()) private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*".toRegex()) private val lpar: Token by literalToken("(") @@ -41,23 +42,10 @@ public object ArithmeticsEvaluator : Grammar() { private val div: Token by literalToken("/") private val minus: Token by literalToken("-") private val plus: Token by literalToken("+") - - @Suppress("unused") private val ws: Token by regexToken("\\s+".toRegex(), ignore = true) - // TODO Rewrite as custom parser to handle numbers with better precision. Currently, numbers like 1e10 are handled while they could be stored as longs without precision loss. - private val number: Parser by num use { - val d = text.toDoubleOrNull() - - MST.Numeric( - if (d == null || d == floor(d) && !d.isInfinite()) { - text.toLongOrNull() ?: text.toDouble() - } else - d - ) - } - - private val singular: Parser by id use { Symbol(text) } + private val number: Parser by num use { MST.Numeric(text.toDouble()) } + private val singular: Parser by id use { MST.Symbolic(text) } private val unaryFunction: Parser by (id and -lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) .map { (id, term) -> MST.Unary(id.text, term) } @@ -74,7 +62,7 @@ public object ArithmeticsEvaluator : Grammar() { .or(binaryFunction) .or(unaryFunction) .or(singular) - .or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(GroupOps.MINUS_OPERATION, it) }) + .or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(GroupOperations.MINUS_OPERATION, it) }) .or(-lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) private val powChain: Parser by leftAssociative(term = term, operator = pow) { a, _, b -> @@ -86,9 +74,9 @@ public object ArithmeticsEvaluator : Grammar() { operator = div or mul use TokenMatch::type ) { a, op, b -> if (op == div) - MST.Binary(FieldOps.DIV_OPERATION, a, b) + MST.Binary(FieldOperations.DIV_OPERATION, a, b) else - MST.Binary(RingOps.TIMES_OPERATION, a, b) + MST.Binary(RingOperations.TIMES_OPERATION, a, b) } private val subSumChain: Parser by leftAssociative( @@ -96,17 +84,16 @@ public object ArithmeticsEvaluator : Grammar() { operator = plus or minus use TokenMatch::type ) { a, op, b -> if (op == plus) - MST.Binary(GroupOps.PLUS_OPERATION, a, b) + MST.Binary(GroupOperations.PLUS_OPERATION, a, b) else - MST.Binary(GroupOps.MINUS_OPERATION, a, b) + MST.Binary(GroupOperations.MINUS_OPERATION, a, b) } override val rootParser: Parser by subSumChain } /** - * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or - * error. + * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or error. * * @receiver the string to parse. * @return the [MST] node. diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt deleted file mode 100644 index ec66be830..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast.rendering - -internal actual fun Double.multiplatformToString(): String = toString() -internal actual fun Float.multiplatformToString(): String = toString() diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt new file mode 100644 index 000000000..77cfb2241 --- /dev/null +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.asm + +import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.complex.toComplex +import space.kscience.kmath.expressions.* +import space.kscience.kmath.misc.Symbol.Companion.x +import space.kscience.kmath.operations.ByteRing +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class TestAsmConsistencyWithInterpreter { + + @Test + fun mstSpace() { + + val mst = MstGroup { + binaryOperationFunction("+")( + unaryOperationFunction("+")( + number(3.toByte()) - (number(2.toByte()) + (scale( + add(number(1), number(1)), + 2.0 + ) + number(1.toByte()) * 3.toByte() - number(1.toByte()))) + ), + + number(1) + ) + bindSymbol("x") + zero + } + + assertEquals( + mst.interpret(MstGroup, x to MST.Numeric(2)), + mst.compile(MstGroup, x to MST.Numeric(2)) + ) + } + + @Test + fun byteRing() { + val mst = MstRing { + binaryOperationFunction("+")( + unaryOperationFunction("+")( + (bindSymbol("x") - (2.toByte() + (scale( + add(number(1), number(1)), + 2.0 + ) + 1.toByte()))) * 3.0 - 1.toByte() + ), + + number(1) + ) * number(2) + } + + assertEquals( + mst.interpret(ByteRing, x to 3.toByte()), + mst.compile(ByteRing, x to 3.toByte()) + ) + } + + @Test + fun realField() { + val mst = MstField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( + (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + } + + assertEquals( + mst.interpret(DoubleField, x to 2.0), + mst.compile(DoubleField, x to 2.0) + ) + } + + @Test + fun complexField() { + val mst = MstField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( + (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + } + + assertEquals( + mst.interpret(ComplexField, x to 2.0.toComplex()), + mst.compile(ComplexField, x to 2.0.toComplex()) + ) + } +} diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmOperationsSupport.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmOperationsSupport.kt new file mode 100644 index 000000000..757235fb7 --- /dev/null +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmOperationsSupport.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.asm + +import space.kscience.kmath.expressions.MstExtendedField +import space.kscience.kmath.expressions.MstField +import space.kscience.kmath.expressions.MstGroup +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class TestAsmOperationsSupport { + @Test + fun testUnaryOperationInvocation() { + val expression = MstGroup { -bindSymbol("x") }.compileToExpression(DoubleField) + val res = expression("x" to 2.0) + assertEquals(-2.0, res) + } + + @Test + fun testBinaryOperationInvocation() { + val expression = MstGroup { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField) + val res = expression("x" to 2.0) + assertEquals(-1.0, res) + } + + @Test + fun testConstProductInvocation() { + val res = MstField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0) + assertEquals(4.0, res) + } + + @Test + fun testMultipleCalls() { + val e = + MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) } + .compileToExpression(DoubleField) + val r = Random(0) + var s = 0.0 + repeat(1000000) { s += e("x" to r.nextDouble()) } + println(s) + } +} diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmSpecialization.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmSpecialization.kt new file mode 100644 index 000000000..b09d79515 --- /dev/null +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmSpecialization.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.asm + +import space.kscience.kmath.expressions.MstExtendedField +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class TestAsmSpecialization { + @Test + fun testUnaryPlus() { + val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField) + assertEquals(2.0, expr("x" to 2.0)) + } + + @Test + fun testUnaryMinus() { + val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField) + assertEquals(-2.0, expr("x" to 2.0)) + } + + @Test + fun testAdd() { + val expr = MstExtendedField { + binaryOperationFunction("+")(bindSymbol("x"), + bindSymbol("x")) + }.compileToExpression(DoubleField) + assertEquals(4.0, expr("x" to 2.0)) + } + + @Test + fun testSine() { + val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField) + assertEquals(0.0, expr("x" to 0.0)) + } + + @Test + fun testMinus() { + val expr = MstExtendedField { + binaryOperationFunction("-")(bindSymbol("x"), + bindSymbol("x")) + }.compileToExpression(DoubleField) + assertEquals(0.0, expr("x" to 2.0)) + } + + @Test + fun testDivide() { + val expr = MstExtendedField { + binaryOperationFunction("/")(bindSymbol("x"), + bindSymbol("x")) + }.compileToExpression(DoubleField) + assertEquals(1.0, expr("x" to 2.0)) + } + + @Test + fun testPower() { + val expr = MstExtendedField { + binaryOperationFunction("pow")(bindSymbol("x"), number(2)) + }.compileToExpression(DoubleField) + + assertEquals(4.0, expr("x" to 2.0)) + } +} diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmVariables.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmVariables.kt new file mode 100644 index 000000000..740326a59 --- /dev/null +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/asm/TestAsmVariables.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.asm + +import space.kscience.kmath.expressions.MstRing +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.operations.ByteRing +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +internal class TestAsmVariables { + @Test + fun testVariable() { + val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing) + assertEquals(1.toByte(), expr("x" to 1.toByte())) + } + + @Test + fun testUndefinedVariableFails() { + val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing) + assertFailsWith { expr() } + } +} diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/ParserPrecedenceTest.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/ParserPrecedenceTest.kt new file mode 100644 index 000000000..6273eff27 --- /dev/null +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/ParserPrecedenceTest.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.ast + +import space.kscience.kmath.expressions.evaluate +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.Field +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class ParserPrecedenceTest { + private val f: Field = DoubleField + + @Test + fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath())) + + @Test + fun test2(): Unit = assertEquals(6.0, f.evaluate("2+2*2".parseMath())) + + @Test + fun test3(): Unit = assertEquals(10.0, f.evaluate("2^3+2".parseMath())) + + @Test + fun test4(): Unit = assertEquals(10.0, f.evaluate("2+2^3".parseMath())) + + @Test + fun test5(): Unit = assertEquals(16.0, f.evaluate("2^3*2".parseMath())) + + @Test + fun test6(): Unit = assertEquals(16.0, f.evaluate("2*2^3".parseMath())) + + @Test + fun test7(): Unit = assertEquals(18.0, f.evaluate("2+2^3*2".parseMath())) + + @Test + fun test8(): Unit = assertEquals(18.0, f.evaluate("2*2^3+2".parseMath())) +} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/ParserTest.kt similarity index 64% rename from kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt rename to kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/ParserTest.kt index d3c203903..53afaa674 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/ParserTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,37 +7,46 @@ package space.kscience.kmath.ast import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.expressions.MstField +import space.kscience.kmath.expressions.evaluate import space.kscience.kmath.expressions.interpret import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals -internal class TestParser { +internal class ParserTest { @Test - fun evaluateParsedMst() { + fun `evaluate MST`() { val mst = "2+2*(2+2)".parseMath() - val res = mst.interpret(ComplexField) + val res = ComplexField.evaluate(mst) assertEquals(Complex(10.0, 0.0), res) } @Test - fun evaluateMstSymbol() { + fun `evaluate MSTExpression`() { + val res = MstField.invoke { number(2) + number(2) * (number(2) + number(2)) }.interpret(ComplexField) + assertEquals(Complex(10.0, 0.0), res) + } + + @Test + fun `evaluate MST with singular`() { val mst = "i".parseMath() - val res = mst.interpret(ComplexField) + val res = ComplexField.evaluate(mst) assertEquals(ComplexField.i, res) } @Test - fun evaluateMstUnary() { + fun `evaluate MST with unary function`() { val mst = "sin(0)".parseMath() - val res = mst.interpret(DoubleField) + val res = DoubleField.evaluate(mst) assertEquals(0.0, res) } @Test - fun evaluateMstBinary() { + fun `evaluate MST with binary function`() { val magicalAlgebra = object : Algebra { override fun bindSymbolOrNull(value: String): String = value @@ -53,7 +62,7 @@ internal class TestParser { } val mst = "magic(a, b)".parseMath() - val res = mst.interpret(magicalAlgebra) + val res = magicalAlgebra.evaluate(mst) assertEquals("a ★ b", res) } } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt similarity index 67% rename from kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt rename to kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt index 7b5ec5765..1584293ce 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -42,22 +42,6 @@ internal class TestFeatures { testLatex(Numeric(1.1e-10), "1.1\\times10^{-10}") testLatex(Numeric(-1.1e-10), "-1.1\\times10^{-10}") testLatex(Numeric(-1.1e10), "-1.1\\times10^{10}") - testLatex(Numeric(0.001), "0.001") - testLatex(Numeric(0.0000001), "1\\times10^{-7}") - - testLatex(Numeric(Float.NaN), "NaN") - testLatex(Numeric(Float.POSITIVE_INFINITY), "\\infty") - testLatex(Numeric(Float.NEGATIVE_INFINITY), "-\\infty") - testLatex(Numeric(1.0f), "1") - testLatex(Numeric(-1.0f), "-1") - testLatex(Numeric(1.42f), "1.42") - testLatex(Numeric(-1.42f), "-1.42") - testLatex(Numeric(1e10f), "1\\times10^{10}") - testLatex(Numeric(1e-10f), "1\\times10^{-10}") - testLatex(Numeric(-1e-10f), "-1\\times10^{-10}") - testLatex(Numeric(-1e10f), "-1\\times10^{10}") - testLatex(Numeric(0.001f), "0.001") - testLatex(Numeric(0.0000001f), "1\\times10^{-7}") } @Test @@ -99,17 +83,13 @@ internal class TestFeatures { fun multiplication() = testLatex("x*1", "x\\times1") @Test - fun inverseTrigonometric() { - testLatex("asin(x)", "\\operatorname{arcsin}\\,\\left(x\\right)") - testLatex("acos(x)", "\\operatorname{arccos}\\,\\left(x\\right)") - testLatex("atan(x)", "\\operatorname{arctan}\\,\\left(x\\right)") - } - - @Test - fun inverseHyperbolic() { - testLatex("asinh(x)", "\\operatorname{arsinh}\\,\\left(x\\right)") - testLatex("acosh(x)", "\\operatorname{arcosh}\\,\\left(x\\right)") - testLatex("atanh(x)", "\\operatorname{artanh}\\,\\left(x\\right)") + fun inverseTrigonometry() { + testLatex("asin(x)", "\\operatorname{sin}^{-1}\\,\\left(x\\right)") + testLatex("asinh(x)", "\\operatorname{sinh}^{-1}\\,\\left(x\\right)") + testLatex("acos(x)", "\\operatorname{cos}^{-1}\\,\\left(x\\right)") + testLatex("acosh(x)", "\\operatorname{cosh}^{-1}\\,\\left(x\\right)") + testLatex("atan(x)", "\\operatorname{tan}^{-1}\\,\\left(x\\right)") + testLatex("atanh(x)", "\\operatorname{tanh}^{-1}\\,\\left(x\\right)") } // @Test diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt similarity index 89% rename from kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt rename to kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt index 66c0ae1ae..6322df25d 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,7 +7,7 @@ package space.kscience.kmath.ast.rendering import space.kscience.kmath.ast.rendering.TestUtils.testLatex import space.kscience.kmath.expressions.MST -import space.kscience.kmath.operations.GroupOps +import space.kscience.kmath.operations.GroupOperations import kotlin.test.Test internal class TestLatex { @@ -36,7 +36,7 @@ internal class TestLatex { fun unaryOperator() = testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)") @Test - fun unaryPlus() = testLatex(MST.Unary(GroupOps.PLUS_OPERATION, MST.Numeric(1)), "+1") + fun unaryPlus() = testLatex(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1") @Test fun unaryMinus() = testLatex("-x", "-x") diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt similarity index 93% rename from kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt rename to kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt index 8bc014c54..2d7bfad19 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,7 +7,7 @@ package space.kscience.kmath.ast.rendering import space.kscience.kmath.ast.rendering.TestUtils.testMathML import space.kscience.kmath.expressions.MST -import space.kscience.kmath.operations.GroupOps +import space.kscience.kmath.operations.GroupOperations import kotlin.test.Test internal class TestMathML { @@ -47,7 +47,7 @@ internal class TestMathML { @Test fun unaryPlus() = - testMathML(MST.Unary(GroupOps.PLUS_OPERATION, MST.Numeric(1)), "+1") + testMathML(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1") @Test fun unaryMinus() = testMathML("-x", "-x") diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt similarity index 71% rename from kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt rename to kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt index 306538d5d..a4017fdb4 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -30,17 +30,4 @@ internal class TestStages { testLatex("(x+x)^x+x*x", "\\left(x+x\\right)^{x}+x\\,x") testLatex("x^(x+x)", "x^{x+x}") } - - @Test - fun exponent() { - testLatex("exp(x)", "e^{x}") - testLatex("exp(x/2)", "\\operatorname{exp}\\,\\left(\\frac{x}{2}\\right)") - testLatex("exp(x^2)", "\\operatorname{exp}\\,\\left(x^{2}\\right)") - } - - @Test - fun fraction() { - testLatex("x/y", "\\frac{x}{y}") - testLatex("x^(x/y)", "x^{x/y}") - } } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt similarity index 80% rename from kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt rename to kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt index 79f178eef..7c9400532 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -30,17 +30,17 @@ internal object TestUtils { ) internal fun testMathML(mst: MST, expectedMathML: String) = assertEquals( - expected = "$expectedMathML", + expected = "$expectedMathML", actual = mathML(mst), ) internal fun testMathML(expression: String, expectedMathML: String) = assertEquals( - expected = "$expectedMathML", + expected = "$expectedMathML", actual = mathML(expression.parseMath()), ) internal fun testMathML(expression: MathSyntax, expectedMathML: String) = assertEquals( - expected = "$expectedMathML", + expected = "$expectedMathML", actual = MathMLSyntaxRenderer.renderWithStringBuilder(expression), ) } diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt deleted file mode 100644 index be890273d..000000000 --- a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import space.kscience.kmath.asm.compile as asmCompile -import space.kscience.kmath.asm.compileToExpression as asmCompileToExpression - -private object GenericAsmCompilerTestContext : CompilerTestContext { - override fun MST.compileToExpression(algebra: IntRing): Expression = - asmCompileToExpression(algebra as Algebra) - - override fun MST.compile(algebra: IntRing, arguments: Map): Int = - asmCompile(algebra as Algebra, arguments) - - override fun MST.compileToExpression(algebra: DoubleField): Expression = - asmCompileToExpression(algebra as Algebra) - - override fun MST.compile(algebra: DoubleField, arguments: Map): Double = - asmCompile(algebra as Algebra, arguments) -} - -@OptIn(UnstableKMathAPI::class) -private object PrimitiveAsmCompilerTestContext : CompilerTestContext { - override fun MST.compileToExpression(algebra: IntRing): Expression = asmCompileToExpression(algebra) - override fun MST.compile(algebra: IntRing, arguments: Map): Int = asmCompile(algebra, arguments) - override fun MST.compileToExpression(algebra: DoubleField): Expression = asmCompileToExpression(algebra) - - override fun MST.compile(algebra: DoubleField, arguments: Map): Double = - asmCompile(algebra, arguments) -} - - -internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - action(GenericAsmCompilerTestContext) - action(PrimitiveAsmCompilerTestContext) -} diff --git a/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt deleted file mode 100644 index ec66be830..000000000 --- a/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast.rendering - -internal actual fun Double.multiplatformToString(): String = toString() -internal actual fun Float.multiplatformToString(): String = toString() diff --git a/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt b/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt deleted file mode 100644 index 0674b0492..000000000 --- a/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.ast - -internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { - //doNothing -} \ No newline at end of file diff --git a/kmath-commons/README.md b/kmath-commons/README.md deleted file mode 100644 index 47b61c409..000000000 --- a/kmath-commons/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-commons - -Commons math binding for kmath - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-commons:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-commons:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-commons:0.4.0-dev-1") -} -``` diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index 50fef7ac8..570ac2b74 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -1,19 +1,23 @@ -plugins { - id("space.kscience.gradle.jvm") -} +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +plugins { + kotlin("jvm") + id("ru.mipt.npm.gradle.common") +} description = "Commons math binding for kmath" dependencies { api(project(":kmath-core")) api(project(":kmath-complex")) api(project(":kmath-coroutines")) - api(project(":kmath-optimization")) api(project(":kmath-stat")) api(project(":kmath-functions")) api("org.apache.commons:commons-math3:3.6.1") } readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL } \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt deleted file mode 100644 index 38eaf8868..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("DEPRECATION") - -package space.kscience.kmath.commons.expressions - -import org.apache.commons.math3.analysis.differentiation.DerivativeStructure -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOps - -/** - * A field over commons-math [DerivativeStructure]. - * - * @property order The derivation order. - * @param bindings The map of bindings values. All bindings are considered free parameters - */ -@OptIn(UnstableKMathAPI::class) -@Deprecated("Use generic DSAlgebra from the core") -public class CmDsField( - public val order: Int, - bindings: Map, -) : ExtendedField, ExpressionAlgebra, - NumbersAddOps { - public val numberOfVariables: Int = bindings.size - - override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } - override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) } - - override fun number(value: Number): DerivativeStructure = const(value.toDouble()) - - /** - * A class implementing both [DerivativeStructure] and [Symbol]. - */ - public inner class DerivativeStructureSymbol( - size: Int, - index: Int, - symbol: Symbol, - value: Double, - ) : DerivativeStructure(size, order, index, value), Symbol { - override val identity: String = symbol.identity - override fun toString(): String = identity - override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity - override fun hashCode(): Int = identity.hashCode() - } - - /** - * Identity-based symbol bindings map - */ - private val variables: Map = bindings.entries.mapIndexed { index, (key, value) -> - key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value) - }.toMap() - - override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value) - - override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[value] - override fun bindSymbol(value: String): DerivativeStructureSymbol = variables.getValue(value) - - public fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity] - public fun bindSymbol(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity) - - public fun DerivativeStructure.derivative(symbols: List): Double { - require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" } - val ordersCount = symbols.map { it.identity }.groupBy { it }.mapValues { it.value.size } - return getPartialDerivative(*variables.keys.map { ordersCount[it] ?: 0 }.toIntArray()) - } - - public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList()) - - override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() - - override fun add(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.add(right) - - override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value) - - override fun multiply(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.multiply(right) - override fun divide(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.divide(right) - override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin() - override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos() - override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.tan() - override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin() - override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos() - override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan() - override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh() - override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh() - override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh() - override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.asinh() - override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.acosh() - override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.atanh() - - override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { - is Double -> arg.pow(pow) - is Int -> arg.pow(pow) - else -> arg.pow(pow.toDouble()) - } - - public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure = arg.pow(pow) - override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() - override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() - - override operator fun DerivativeStructure.plus(other: Number): DerivativeStructure = add(other.toDouble()) - override operator fun DerivativeStructure.minus(other: Number): DerivativeStructure = subtract(other.toDouble()) - override operator fun Number.plus(other: DerivativeStructure): DerivativeStructure = other + this - override operator fun Number.minus(other: DerivativeStructure): DerivativeStructure = other - this -} - -/** - * Auto-diff processor based on Commons-math [DerivativeStructure] - */ -@Deprecated("Use generic DSAlgebra from the core") -public object CmDsProcessor : AutoDiffProcessor { - override fun differentiate( - function: CmDsField.() -> DerivativeStructure, - ): CmDsExpression = CmDsExpression(function) -} - -/** - * A constructs that creates a derivative structure with required order on-demand - */ -@Deprecated("Use generic DSAlgebra from the core") -public class CmDsExpression( - public val function: CmDsField.() -> DerivativeStructure, -) : DifferentiableExpression { - override operator fun invoke(arguments: Map): Double = - CmDsField(0, arguments).function().value - - /** - * Get the derivative expression with given orders - */ - override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> - with(CmDsField(symbols.size, arguments)) { function().derivative(symbols) } - } -} diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt new file mode 100644 index 000000000..736685789 --- /dev/null +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -0,0 +1,130 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.commons.expressions + +import org.apache.commons.math3.analysis.differentiation.DerivativeStructure +import space.kscience.kmath.expressions.* +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.NumbersAddOperations + +/** + * A field over commons-math [DerivativeStructure]. + * + * @property order The derivation order. + * @property bindings The map of bindings values. All bindings are considered free parameters + */ +@OptIn(UnstableKMathAPI::class) +public class DerivativeStructureField( + public val order: Int, + bindings: Map, +) : ExtendedField, ExpressionAlgebra, + NumbersAddOperations { + public val numberOfVariables: Int = bindings.size + + public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } + public override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) } + + public override fun number(value: Number): DerivativeStructure = const(value.toDouble()) + + /** + * A class that implements both [DerivativeStructure] and a [Symbol] + */ + public inner class DerivativeStructureSymbol( + size: Int, + index: Int, + symbol: Symbol, + value: Double, + ) : DerivativeStructure(size, order, index, value), Symbol { + public override val identity: String = symbol.identity + public override fun toString(): String = identity + public override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity + public override fun hashCode(): Int = identity.hashCode() + } + + /** + * Identity-based symbol bindings map + */ + private val variables: Map = bindings.entries.mapIndexed { index, (key, value) -> + key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value) + }.toMap() + + public override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value) + + public override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[value] + public override fun bindSymbol(value: String): DerivativeStructureSymbol = variables.getValue(value) + + public fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity] + public fun bindSymbol(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity) + + public fun DerivativeStructure.derivative(symbols: List): Double { + require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" } + val ordersCount = symbols.map { it.identity }.groupBy { it }.mapValues { it.value.size } + return getPartialDerivative(*variables.keys.map { ordersCount[it] ?: 0 }.toIntArray()) + } + + public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList()) + + public override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() + + public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) + + public override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value) + + public override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b) + public override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b) + public override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin() + public override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos() + public override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.tan() + public override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin() + public override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos() + public override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan() + public override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh() + public override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh() + public override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh() + public override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.asinh() + public override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.acosh() + public override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.atanh() + + public override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { + is Double -> arg.pow(pow) + is Int -> arg.pow(pow) + else -> arg.pow(pow.toDouble()) + } + + public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure = arg.pow(pow) + public override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() + public override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() + + public override operator fun DerivativeStructure.plus(b: Number): DerivativeStructure = add(b.toDouble()) + public override operator fun DerivativeStructure.minus(b: Number): DerivativeStructure = subtract(b.toDouble()) + public override operator fun Number.plus(b: DerivativeStructure): DerivativeStructure = b + this + public override operator fun Number.minus(b: DerivativeStructure): DerivativeStructure = b - this + + public companion object : + AutoDiffProcessor> { + public override fun process(function: DerivativeStructureField.() -> DerivativeStructure): DifferentiableExpression> = + DerivativeStructureExpression(function) + } +} + +/** + * A constructs that creates a derivative structure with required order on-demand + */ +public class DerivativeStructureExpression( + public val function: DerivativeStructureField.() -> DerivativeStructure, +) : DifferentiableExpression> { + public override operator fun invoke(arguments: Map): Double = + DerivativeStructureField(0, arguments).function().value + + /** + * Get the derivative expression with given orders + */ + public override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> + with(DerivativeStructureField(symbols.size, arguments)) { function().derivative(symbols) } + } +} diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt index c3e581d31..535c6b39e 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,8 +7,8 @@ package space.kscience.kmath.commons.integration import org.apache.commons.math3.analysis.integration.IterativeLegendreGaussIntegrator import org.apache.commons.math3.analysis.integration.SimpsonIntegrator -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.integration.* +import space.kscience.kmath.misc.UnstableKMathAPI /** * Integration wrapper for Common-maths UnivariateIntegrator @@ -18,11 +18,17 @@ public class CMIntegrator( public val integratorBuilder: (Integrand) -> org.apache.commons.math3.analysis.integration.UnivariateIntegrator, ) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { + public class TargetRelativeAccuracy(public val value: Double) : IntegrandFeature + public class TargetAbsoluteAccuracy(public val value: Double) : IntegrandFeature + + public class MinIterations(public val value: Int) : IntegrandFeature + public class MaxIterations(public val value: Int) : IntegrandFeature + + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val integrator = integratorBuilder(integrand) val maxCalls = integrand.getFeature()?.maxCalls ?: defaultMaxCalls val remainingCalls = maxCalls - integrand.calls - val range = integrand.getFeature()?.range + val range = integrand.getFeature>()?.range ?: error("Integration range is not provided") val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive) @@ -39,15 +45,16 @@ public class CMIntegrator( * Create a Simpson integrator based on [SimpsonIntegrator] */ public fun simpson(defaultMaxCalls: Int = 200): CMIntegrator = CMIntegrator(defaultMaxCalls) { integrand -> - val absoluteAccuracy = integrand.getFeature()?.accuracy + val absoluteAccuracy = integrand.getFeature()?.value ?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY - val relativeAccuracy = integrand.getFeature()?.accuracy + val relativeAccuracy = integrand.getFeature()?.value ?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY - val iterations = integrand.getFeature()?.range - ?: SimpsonIntegrator.DEFAULT_MIN_ITERATIONS_COUNT..SimpsonIntegrator.SIMPSON_MAX_ITERATIONS_COUNT + val minIterations = integrand.getFeature()?.value + ?: SimpsonIntegrator.DEFAULT_MIN_ITERATIONS_COUNT + val maxIterations = integrand.getFeature()?.value + ?: SimpsonIntegrator.SIMPSON_MAX_ITERATIONS_COUNT - - SimpsonIntegrator(relativeAccuracy, absoluteAccuracy, iterations.first, iterations.last) + SimpsonIntegrator(relativeAccuracy, absoluteAccuracy, minIterations, maxIterations) } /** @@ -55,19 +62,21 @@ public class CMIntegrator( */ public fun legandre(numPoints: Int, defaultMaxCalls: Int = numPoints * 5): CMIntegrator = CMIntegrator(defaultMaxCalls) { integrand -> - val absoluteAccuracy = integrand.getFeature()?.accuracy + val absoluteAccuracy = integrand.getFeature()?.value ?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY - val relativeAccuracy = integrand.getFeature()?.accuracy + val relativeAccuracy = integrand.getFeature()?.value ?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY - val iterations = integrand.getFeature()?.range - ?: IterativeLegendreGaussIntegrator.DEFAULT_MIN_ITERATIONS_COUNT..IterativeLegendreGaussIntegrator.DEFAULT_MAX_ITERATIONS_COUNT + val minIterations = integrand.getFeature()?.value + ?: IterativeLegendreGaussIntegrator.DEFAULT_MIN_ITERATIONS_COUNT + val maxIterations = integrand.getFeature()?.value + ?: IterativeLegendreGaussIntegrator.DEFAULT_MAX_ITERATIONS_COUNT IterativeLegendreGaussIntegrator( numPoints, relativeAccuracy, absoluteAccuracy, - iterations.first, - iterations.last + minIterations, + maxIterations ) } } @@ -75,14 +84,14 @@ public class CMIntegrator( @UnstableKMathAPI public var MutableList.targetAbsoluteAccuracy: Double? - get() = filterIsInstance().lastOrNull()?.accuracy + get() = filterIsInstance().lastOrNull()?.value set(value) { - value?.let { add(IntegrandAbsoluteAccuracy(value)) } + value?.let { add(CMIntegrator.TargetAbsoluteAccuracy(value)) } } @UnstableKMathAPI public var MutableList.targetRelativeAccuracy: Double? - get() = filterIsInstance().lastOrNull()?.accuracy + get() = filterIsInstance().lastOrNull()?.value set(value) { - value?.let { add(IntegrandRelativeAccuracy(value)) } + value?.let { add(CMIntegrator.TargetRelativeAccuracy(value)) } } \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/GaussRuleIntegrator.kt similarity index 88% rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt rename to kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/GaussRuleIntegrator.kt index 263463d37..071bac315 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/GaussRuleIntegrator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.commons.integration @@ -11,13 +11,13 @@ import space.kscience.kmath.integration.* /** * A simple one-pass integrator based on Gauss rule */ -public class CMGaussRuleIntegrator( +public class GaussRuleIntegrator( private val numpoints: Int, private var type: GaussRule = GaussRule.LEGANDRE, ) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { - val range = integrand.getFeature()?.range + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { + val range = integrand.getFeature>()?.range ?: error("Integration range is not provided") val integrator: GaussIntegrator = getIntegrator(range) //TODO check performance @@ -76,8 +76,8 @@ public class CMGaussRuleIntegrator( numPoints: Int = 100, type: GaussRule = GaussRule.LEGANDRE, function: (Double) -> Double, - ): Double = CMGaussRuleIntegrator(numPoints, type).process( + ): Double = GaussRuleIntegrator(numPoints, type).integrate( UnivariateIntegrand(function, IntegrationRange(range)) - ).value + ).value!! } } \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt index d19bd1be0..11b097831 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt @@ -1,36 +1,32 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.commons.linear import org.apache.commons.math3.linear.* -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.* +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import kotlin.reflect.KClass import kotlin.reflect.cast public class CMMatrix(public val origin: RealMatrix) : Matrix { - override val rowNum: Int get() = origin.rowDimension - override val colNum: Int get() = origin.columnDimension + public override val rowNum: Int get() = origin.rowDimension + public override val colNum: Int get() = origin.columnDimension - override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) + public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) } -@JvmInline -public value class CMVector(public val origin: RealVector) : Point { - override val size: Int get() = origin.dimension +public class CMVector(public val origin: RealVector) : Point { + public override val size: Int get() = origin.dimension - override operator fun get(index: Int): Double = origin.getEntry(index) + public override operator fun get(index: Int): Double = origin.getEntry(index) - override operator fun iterator(): Iterator = origin.toArray().iterator() - - override fun toString(): String = Buffer.toString(this) + public override operator fun iterator(): Iterator = origin.toArray().iterator() } public fun RealVector.toPoint(): CMVector = CMVector(this) @@ -38,7 +34,7 @@ public fun RealVector.toPoint(): CMVector = CMVector(this) public object CMLinearSpace : LinearSpace { override val elementAlgebra: DoubleField get() = DoubleField - override fun buildMatrix( + public override fun buildMatrix( rows: Int, columns: Int, initializer: DoubleField.(i: Int, j: Int) -> Double, @@ -77,16 +73,16 @@ public object CMLinearSpace : LinearSpace { override fun Point.minus(other: Point): CMVector = toCM().origin.subtract(other.toCM().origin).wrap() - override fun Matrix.dot(other: Matrix): CMMatrix = + public override fun Matrix.dot(other: Matrix): CMMatrix = toCM().origin.multiply(other.toCM().origin).wrap() - override fun Matrix.dot(vector: Point): CMVector = + public override fun Matrix.dot(vector: Point): CMVector = toCM().origin.preMultiply(vector.toCM().origin).wrap() - override operator fun Matrix.minus(other: Matrix): CMMatrix = + public override operator fun Matrix.minus(other: Matrix): CMMatrix = toCM().origin.subtract(other.toCM().origin).wrap() - override operator fun Matrix.times(value: Double): CMMatrix = + public override operator fun Matrix.times(value: Double): CMMatrix = toCM().origin.scalarMultiply(value).wrap() override fun Double.times(m: Matrix): CMMatrix = @@ -99,7 +95,7 @@ public object CMLinearSpace : LinearSpace { v * this @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { //Return the feature if it is intrinsic to the structure structure.getFeature(type)?.let { return it } @@ -113,22 +109,22 @@ public object CMLinearSpace : LinearSpace { LupDecompositionFeature { private val lup by lazy { LUDecomposition(origin) } override val determinant: Double by lazy { lup.determinant } - override val l: Matrix by lazy> { CMMatrix(lup.l).withFeature(LFeature) } - override val u: Matrix by lazy> { CMMatrix(lup.u).withFeature(UFeature) } + override val l: Matrix by lazy { CMMatrix(lup.l) + LFeature } + override val u: Matrix by lazy { CMMatrix(lup.u) + UFeature } override val p: Matrix by lazy { CMMatrix(lup.p) } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy> { + override val l: Matrix by lazy { val cholesky = CholeskyDecomposition(origin) - CMMatrix(cholesky.l).withFeature(LFeature) + CMMatrix(cholesky.l) + LFeature } } QRDecompositionFeature::class -> object : QRDecompositionFeature { private val qr by lazy { QRDecomposition(origin) } - override val q: Matrix by lazy> { CMMatrix(qr.q).withFeature(OrthogonalFeature) } - override val r: Matrix by lazy> { CMMatrix(qr.r).withFeature(UFeature) } + override val q: Matrix by lazy { CMMatrix(qr.q) + OrthogonalFeature } + override val r: Matrix by lazy { CMMatrix(qr.r) + UFeature } } SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt index 19799aab3..ee602ca06 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt @@ -1,12 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.commons.linear import org.apache.commons.math3.linear.* -import space.kscience.kmath.linear.LinearSolver import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.Point @@ -18,7 +17,7 @@ public enum class CMDecomposition { CHOLESKY } -private fun CMLinearSpace.solver( +public fun CMLinearSpace.solver( a: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP, ): DecompositionSolver = when (decomposition) { @@ -45,14 +44,3 @@ public fun CMLinearSpace.inverse( a: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP, ): CMMatrix = solver(a, decomposition).inverse.wrap() - - -public fun CMLinearSpace.solver(decomposition: CMDecomposition): LinearSolver = object : LinearSolver { - override fun solve(a: Matrix, b: Matrix): Matrix = solver(a, decomposition).solve(b.toCM().origin).wrap() - - override fun solve(a: Matrix, b: Point): Point = solver(a, decomposition).solve(b.toCM().origin).toPoint() - - override fun inverse(matrix: Matrix): Matrix = solver(matrix, decomposition).inverse.wrap() -} - -public fun CMLinearSpace.lupSolver(): LinearSolver = solver((CMDecomposition.LUP)) \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt new file mode 100644 index 000000000..cfb8c39be --- /dev/null +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt @@ -0,0 +1,129 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.commons.optimization + +import org.apache.commons.math3.optim.* +import org.apache.commons.math3.optim.nonlinear.scalar.GoalType +import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer +import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction +import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient +import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.SymbolIndexer +import space.kscience.kmath.expressions.derivative +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.optimization.* +import kotlin.reflect.KClass + +public operator fun PointValuePair.component1(): DoubleArray = point +public operator fun PointValuePair.component2(): Double = value + +@OptIn(UnstableKMathAPI::class) +public class CMOptimization( + override val symbols: List, +) : FunctionOptimization, NoDerivFunctionOptimization, SymbolIndexer, OptimizationFeature { + + private val optimizationData: HashMap, OptimizationData> = HashMap() + private var optimizerBuilder: (() -> MultivariateOptimizer)? = null + public var convergenceChecker: ConvergenceChecker = SimpleValueChecker( + DEFAULT_RELATIVE_TOLERANCE, + DEFAULT_ABSOLUTE_TOLERANCE, + DEFAULT_MAX_ITER + ) + + override var maximize: Boolean + get() = optimizationData[GoalType::class] == GoalType.MAXIMIZE + set(value) { + optimizationData[GoalType::class] = if (value) GoalType.MAXIMIZE else GoalType.MINIMIZE + } + + public fun addOptimizationData(data: OptimizationData) { + optimizationData[data::class] = data + } + + init { + addOptimizationData(MaxEval.unlimited()) + } + + public fun exportOptimizationData(): List = optimizationData.values.toList() + + public override fun initialGuess(map: Map): Unit { + addOptimizationData(InitialGuess(map.toDoubleArray())) + } + + public override fun function(expression: Expression): Unit { + val objectiveFunction = ObjectiveFunction { + val args = it.toMap() + expression(args) + } + addOptimizationData(objectiveFunction) + } + + public override fun diffFunction(expression: DifferentiableExpression>) { + function(expression) + val gradientFunction = ObjectiveFunctionGradient { + val args = it.toMap() + DoubleArray(symbols.size) { index -> + expression.derivative(symbols[index])(args) + } + } + addOptimizationData(gradientFunction) + if (optimizerBuilder == null) { + optimizerBuilder = { + NonLinearConjugateGradientOptimizer( + NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, + convergenceChecker + ) + } + } + } + + public fun simplex(simplex: AbstractSimplex) { + addOptimizationData(simplex) + //Set optimization builder to simplex if it is not present + if (optimizerBuilder == null) { + optimizerBuilder = { SimplexOptimizer(convergenceChecker) } + } + } + + public fun simplexSteps(steps: Map) { + simplex(NelderMeadSimplex(steps.toDoubleArray())) + } + + public fun goal(goalType: GoalType) { + addOptimizationData(goalType) + } + + public fun optimizer(block: () -> MultivariateOptimizer) { + optimizerBuilder = block + } + + override fun update(result: OptimizationResult) { + initialGuess(result.point) + } + + override fun optimize(): OptimizationResult { + val optimizer = optimizerBuilder?.invoke() ?: error("Optimizer not defined") + val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray()) + return OptimizationResult(point.toMap(), value, setOf(this)) + } + + public companion object : OptimizationProblemFactory { + public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 + public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 + public const val DEFAULT_MAX_ITER: Int = 1000 + + override fun build(symbols: List): CMOptimization = CMOptimization(symbols) + } +} + +public fun CMOptimization.initialGuess(vararg pairs: Pair): Unit = initialGuess(pairs.toMap()) +public fun CMOptimization.simplexSteps(vararg pairs: Pair): Unit = simplexSteps(pairs.toMap()) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt deleted file mode 100644 index c4dafb6a6..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -@file:OptIn(UnstableKMathAPI::class) -package space.kscience.kmath.commons.optimization - -import org.apache.commons.math3.optim.* -import org.apache.commons.math3.optim.nonlinear.scalar.GoalType -import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer -import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction -import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient -import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.SymbolIndexer -import space.kscience.kmath.expressions.derivative -import space.kscience.kmath.expressions.withSymbols -import space.kscience.kmath.misc.log -import space.kscience.kmath.optimization.* -import kotlin.collections.set -import kotlin.reflect.KClass - -public operator fun PointValuePair.component1(): DoubleArray = point -public operator fun PointValuePair.component2(): Double = value - -public class CMOptimizerEngine(public val optimizerBuilder: () -> MultivariateOptimizer) : OptimizationFeature { - override fun toString(): String = "CMOptimizer($optimizerBuilder)" -} - -/** - * Specify a Commons-maths optimization engine - */ -public fun FunctionOptimizationBuilder.cmEngine(optimizerBuilder: () -> MultivariateOptimizer) { - addFeature(CMOptimizerEngine(optimizerBuilder)) -} - -public class CMOptimizerData(public val data: List OptimizationData>) : OptimizationFeature { - public constructor(vararg data: (SymbolIndexer.() -> OptimizationData)) : this(data.toList()) - - override fun toString(): String = "CMOptimizerData($data)" -} - -/** - * Specify Commons-maths optimization data. - */ -public fun FunctionOptimizationBuilder.cmOptimizationData(data: SymbolIndexer.() -> OptimizationData) { - updateFeature { - val newData = (it?.data ?: emptyList()) + data - CMOptimizerData(newData) - } -} - -public fun FunctionOptimizationBuilder.simplexSteps(vararg steps: Pair) { - //TODO use convergence checker from features - cmEngine { SimplexOptimizer(CMOptimizer.defaultConvergenceChecker) } - cmOptimizationData { NelderMeadSimplex(mapOf(*steps).toDoubleArray()) } -} - -@OptIn(UnstableKMathAPI::class) -public object CMOptimizer : Optimizer> { - - public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 - public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 - public const val DEFAULT_MAX_ITER: Int = 1000 - - public val defaultConvergenceChecker: SimpleValueChecker = SimpleValueChecker( - DEFAULT_RELATIVE_TOLERANCE, - DEFAULT_ABSOLUTE_TOLERANCE, - DEFAULT_MAX_ITER - ) - - - override suspend fun optimize( - problem: FunctionOptimization, - ): FunctionOptimization { - val startPoint = problem.startPoint - - val parameters = problem.getFeature()?.symbols - ?: problem.getFeature>()?.point?.keys - ?: startPoint.keys - - - withSymbols(parameters) { - val convergenceChecker: ConvergenceChecker = SimpleValueChecker( - DEFAULT_RELATIVE_TOLERANCE, - DEFAULT_ABSOLUTE_TOLERANCE, - DEFAULT_MAX_ITER - ) - - val cmOptimizer: MultivariateOptimizer = problem.getFeature()?.optimizerBuilder?.invoke() - ?: NonLinearConjugateGradientOptimizer( - NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, - convergenceChecker - ) - - val optimizationData: HashMap, OptimizationData> = HashMap() - - fun addOptimizationData(data: OptimizationData) { - optimizationData[data::class] = data - } - - addOptimizationData(MaxEval.unlimited()) - addOptimizationData(InitialGuess(startPoint.toDoubleArray())) - - //fun exportOptimizationData(): List = optimizationData.values.toList() - - val objectiveFunction = ObjectiveFunction { - val args = startPoint + it.toMap() - val res = problem.expression(args) - res - } - addOptimizationData(objectiveFunction) - - val gradientFunction = ObjectiveFunctionGradient { - val args = startPoint + it.toMap() - val res = DoubleArray(symbols.size) { index -> - problem.expression.derivative(symbols[index])(args) - } - res - } - addOptimizationData(gradientFunction) - - val logger = problem.getFeature() - - for (feature in problem.features) { - when (feature) { - is CMOptimizerData -> feature.data.forEach { dataBuilder -> - addOptimizationData(dataBuilder()) - } - is FunctionOptimizationTarget -> when (feature) { - FunctionOptimizationTarget.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE) - FunctionOptimizationTarget.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE) - } - else -> logger?.log { "The feature $feature is unused in optimization" } - } - } - - val (point, value) = cmOptimizer.optimize(*optimizationData.values.toTypedArray()) - return problem.withFeatures(OptimizationResult(point.toMap()), OptimizationValue(value)) - } - } -} diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt new file mode 100644 index 000000000..13b5c73f4 --- /dev/null +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.commons.optimization + +import org.apache.commons.math3.analysis.differentiation.DerivativeStructure +import space.kscience.kmath.commons.expressions.DerivativeStructureField +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.optimization.FunctionOptimization +import space.kscience.kmath.optimization.OptimizationResult +import space.kscience.kmath.optimization.noDerivOptimizeWith +import space.kscience.kmath.optimization.optimizeWith +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer + +/** + * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation + */ +public fun FunctionOptimization.Companion.chiSquared( + x: Buffer, + y: Buffer, + yErr: Buffer, + model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, +): DifferentiableExpression> = chiSquared(DerivativeStructureField, x, y, yErr, model) + +/** + * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation + */ +public fun FunctionOptimization.Companion.chiSquared( + x: Iterable, + y: Iterable, + yErr: Iterable, + model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, +): DifferentiableExpression> = chiSquared( + DerivativeStructureField, + x.toList().asBuffer(), + y.toList().asBuffer(), + yErr.toList().asBuffer(), + model +) + +/** + * Optimize expression without derivatives + */ +public fun Expression.optimize( + vararg symbols: Symbol, + configuration: CMOptimization.() -> Unit, +): OptimizationResult = noDerivOptimizeWith(CMOptimization, symbols = symbols, configuration) + +/** + * Optimize differentiable expression + */ +public fun DifferentiableExpression>.optimize( + vararg symbols: Symbol, + configuration: CMOptimization.() -> Unit, +): OptimizationResult = optimizeWith(CMOptimization, symbols = symbols, configuration) + +public fun DifferentiableExpression>.minimize( + vararg startPoint: Pair, + configuration: CMOptimization.() -> Unit = {}, +): OptimizationResult { + val symbols = startPoint.map { it.first }.toTypedArray() + return optimize(*symbols){ + maximize = false + initialGuess(startPoint.toMap()) + diffFunction(this@minimize) + configuration() + } +} \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt index 32962659f..16a6967e2 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt @@ -1,44 +1,39 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.commons.random -import kotlinx.coroutines.runBlocking -import space.kscience.kmath.misc.toIntExact -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.samplers.GaussianSampler -import space.kscience.kmath.stat.next - +import space.kscience.kmath.stat.RandomGenerator public class CMRandomGeneratorWrapper( public val factory: (IntArray) -> RandomGenerator, ) : org.apache.commons.math3.random.RandomGenerator { private var generator: RandomGenerator = factory(intArrayOf()) - override fun nextBoolean(): Boolean = generator.nextBoolean() - override fun nextFloat(): Float = generator.nextDouble().toFloat() + public override fun nextBoolean(): Boolean = generator.nextBoolean() + public override fun nextFloat(): Float = generator.nextDouble().toFloat() - override fun setSeed(seed: Int) { + public override fun setSeed(seed: Int) { generator = factory(intArrayOf(seed)) } - override fun setSeed(seed: IntArray) { + public override fun setSeed(seed: IntArray) { generator = factory(seed) } - override fun setSeed(seed: Long) { - setSeed(seed.toIntExact()) + public override fun setSeed(seed: Long) { + setSeed(seed.toInt()) } - override fun nextBytes(bytes: ByteArray) { + public override fun nextBytes(bytes: ByteArray) { generator.fillBytes(bytes) } - override fun nextInt(): Int = generator.nextInt() - override fun nextInt(n: Int): Int = generator.nextInt(n) - override fun nextGaussian(): Double = runBlocking { GaussianSampler(0.0, 1.0).next(generator) } - override fun nextDouble(): Double = generator.nextDouble() - override fun nextLong(): Long = generator.nextLong() + public override fun nextInt(): Int = generator.nextInt() + public override fun nextInt(n: Int): Int = generator.nextInt(n) + public override fun nextGaussian(): Double = TODO() + public override fun nextDouble(): Double = generator.nextDouble() + public override fun nextLong(): Long = generator.nextLong() } diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt index a77da2d2f..d29491d63 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,22 +10,29 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import org.apache.commons.math3.transform.* import space.kscience.kmath.complex.Complex -import space.kscience.kmath.operations.BufferTransform import space.kscience.kmath.streaming.chunked import space.kscience.kmath.streaming.spread import space.kscience.kmath.structures.* + + /** - * Streaming and buffer transformations with Commons-math algorithms + * Streaming and buffer transformations */ public object Transformations { - private fun Buffer.toCmComplexArray(): Array = + private fun Buffer.toArray(): Array = Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) } + private fun Buffer.asArray() = if (this is DoubleBuffer) { + array + } else { + DoubleArray(size) { i -> get(i) } + } + /** * Create a virtual buffer on top of array */ - private fun Array.asBuffer() = VirtualBuffer(size) { + private fun Array.asBuffer() = VirtualBuffer(size) { val value = get(it) Complex(value.real, value.imaginary) } @@ -33,67 +40,70 @@ public object Transformations { public fun fourier( normalization: DftNormalization = DftNormalization.STANDARD, direction: TransformType = TransformType.FORWARD, - ): BufferTransform = BufferTransform { - FastFourierTransformer(normalization).transform(it.toCmComplexArray(), direction).asBuffer() + ): SuspendBufferTransform = { + FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer() } public fun realFourier( normalization: DftNormalization = DftNormalization.STANDARD, direction: TransformType = TransformType.FORWARD, - ): BufferTransform = BufferTransform { - FastFourierTransformer(normalization).transform(it.toDoubleArray(), direction).asBuffer() + ): SuspendBufferTransform = { + FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer() } public fun sine( normalization: DstNormalization = DstNormalization.STANDARD_DST_I, direction: TransformType = TransformType.FORWARD, - ): BufferTransform = DoubleBufferTransform { - FastSineTransformer(normalization).transform(it.array, direction).asBuffer() + ): SuspendBufferTransform = { + FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer() } public fun cosine( normalization: DctNormalization = DctNormalization.STANDARD_DCT_I, direction: TransformType = TransformType.FORWARD, - ): BufferTransform = BufferTransform { - FastCosineTransformer(normalization).transform(it.toDoubleArray(), direction).asBuffer() + ): SuspendBufferTransform = { + FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer() } public fun hadamard( direction: TransformType = TransformType.FORWARD, - ): BufferTransform = DoubleBufferTransform { - FastHadamardTransformer().transform(it.array, direction).asBuffer() + ): SuspendBufferTransform = { + FastHadamardTransformer().transform(it.asArray(), direction).asBuffer() } } /** * Process given [Flow] with commons-math fft transformation */ -public fun Flow>.fft( +@FlowPreview +public fun Flow>.FFT( normalization: DftNormalization = DftNormalization.STANDARD, direction: TransformType = TransformType.FORWARD, ): Flow> { val transform = Transformations.fourier(normalization, direction) - return map(transform::transform) + return map { transform(it) } } +@FlowPreview @JvmName("realFFT") -public fun Flow>.fft( +public fun Flow>.FFT( normalization: DftNormalization = DftNormalization.STANDARD, direction: TransformType = TransformType.FORWARD, ): Flow> { val transform = Transformations.realFourier(normalization, direction) - return map(transform::transform) + return map(transform) } /** * Process a continuous flow of real numbers in FFT splitting it in chunks of [bufferSize]. */ +@FlowPreview @JvmName("realFFT") -public fun Flow.fft( +public fun Flow.FFT( bufferSize: Int = Int.MAX_VALUE, normalization: DftNormalization = DftNormalization.STANDARD, direction: TransformType = TransformType.FORWARD, -): Flow = chunked(bufferSize).fft(normalization, direction).spread() +): Flow = chunked(bufferSize).FFT(normalization, direction).spread() /** * Map a complex flow into real flow by taking real part of each number diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt index 7c3c086ed..879cd75b1 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt @@ -1,13 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("DEPRECATION") - package space.kscience.kmath.commons.expressions -import space.kscience.kmath.expressions.* +import space.kscience.kmath.expressions.binding +import space.kscience.kmath.expressions.derivative +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.symbol import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.test.Test @@ -17,10 +19,10 @@ import kotlin.test.assertFails internal inline fun diff( order: Int, vararg parameters: Pair, - block: CmDsField.() -> Unit, -) { + block: DerivativeStructureField.() -> Unit, +): Unit { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - CmDsField(order, mapOf(*parameters)).run(block) + DerivativeStructureField(order, mapOf(*parameters)).run(block) } internal class AutoDiffTest { @@ -36,16 +38,16 @@ internal class AutoDiffTest { println(z.derivative(x)) println(z.derivative(y, x)) assertEquals(z.derivative(x, y), z.derivative(y, x)) - // check improper order cause failure + //check that improper order cause failure assertFails { z.derivative(x, x, y) } } } @Test fun autoDifTest() { - val f = CmDsExpression { - val x by binding - val y by binding + val f = DerivativeStructureExpression { + val x by binding() + val y by binding() x.pow(2) + 2 * x * y + y.pow(2) + 1 } diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt index 6541736ce..9d475d04d 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt @@ -1,14 +1,13 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.commons.integration import org.junit.jupiter.api.Test -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.integration.integrate -import space.kscience.kmath.integration.value +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField.sin import kotlin.math.PI import kotlin.math.abs @@ -20,16 +19,16 @@ internal class IntegrationTest { @Test fun simpson() { - val res = CMIntegrator.simpson().integrate(0.0..2 * PI, function = function).value + val res = CMIntegrator.simpson().integrate(0.0..2 * PI, function) assertTrue { abs(res) < 1e-3 } } @Test fun customSimpson() { - val res = CMIntegrator.simpson().integrate(0.0..PI, { + val res = CMIntegrator.simpson().integrate(0.0..PI, function) { targetRelativeAccuracy = 1e-4 targetAbsoluteAccuracy = 1e-4 - }, function).value + } assertTrue { abs(res - 2) < 1e-3 } assertTrue { abs(res - 2) > 1e-12 } } diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt index d2e86bb40..716cd1b0f 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt @@ -1,49 +1,48 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.commons.optimization import kotlinx.coroutines.runBlocking -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.commons.expressions.DerivativeStructureExpression import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.expressions.DSFieldExpression -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.Symbol.Companion.y -import space.kscience.kmath.expressions.autodiff -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.operations.DoubleBufferOps.Companion.map -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.optimization.* -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.stat.chiSquaredExpression -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.misc.symbol +import space.kscience.kmath.optimization.FunctionOptimization +import space.kscience.kmath.stat.RandomGenerator +import kotlin.math.pow import kotlin.test.Test -@OptIn(UnstableKMathAPI::class) internal class OptimizeTest { - val normal = DSFieldExpression(DoubleField) { - exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y).pow(2) / 2) + val x by symbol + val y by symbol + + val normal = DerivativeStructureExpression { + exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y) + .pow(2) / 2) } @Test - fun testGradientOptimization() = runBlocking { - val result = normal.optimizeWith(CMOptimizer, x to 1.0, y to 1.0) - println(result.resultPoint) - println(result.resultValue) + fun testGradientOptimization() { + val result = normal.optimize(x, y) { + initialGuess(x to 1.0, y to 1.0) + //no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function + } + println(result.point) + println(result.value) } @Test - fun testSimplexOptimization() = runBlocking { - val result = normal.optimizeWith(CMOptimizer, x to 1.0, y to 1.0) { + fun testSimplexOptimization() { + val result = normal.optimize(x, y) { + initialGuess(x to 1.0, y to 1.0) simplexSteps(x to 2.0, y to 0.5) //this sets simplex optimizer } - println(result.resultPoint) - println(result.resultValue) + println(result.point) + println(result.value) } @Test @@ -55,27 +54,21 @@ internal class OptimizeTest { val sigma = 1.0 val generator = NormalDistribution(0.0, sigma) val chain = generator.sample(RandomGenerator.default(112667)) - val x = (1..100).map(Int::toDouble).asBuffer() + val x = (1..100).map(Int::toDouble) val y = x.map { it.pow(2) + it + 1 + chain.next() } - val yErr = DoubleBuffer(x.size) { sigma } + val yErr = List(x.size) { sigma } - val chi2 = Double.autodiff.chiSquaredExpression( - x, y, yErr - ) { arg -> + val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 -> val cWithDefault = bindSymbolOrNull(c) ?: one - bindSymbol(a) * arg.pow(2) + bindSymbol(b) * arg + cWithDefault + bindSymbol(a) * x1.pow(2) + bindSymbol(b) * x1 + cWithDefault } - val result: FunctionOptimization = chi2.optimizeWith( - CMOptimizer, - mapOf(a to 1.5, b to 0.9, c to 1.0), - FunctionOptimizationTarget.MINIMIZE - ) + val result = chi2.minimize(a to 1.5, b to 0.9, c to 1.0) println(result) - println("Chi2/dof = ${result.resultValue / (x.size - 3)}") + println("Chi2/dof = ${result.value / (x.size - 3)}") } } diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 4e800b7ac..3a05c3d6d 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -2,33 +2,35 @@ Complex and hypercomplex number systems in KMath. - - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex numbers operations - - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions and their composition + - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers + - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.4.0-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-6`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } - mavenCentral() + maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap } dependencies { - implementation 'space.kscience:kmath-complex:0.4.0-dev-1' + implementation 'space.kscience:kmath-complex:0.3.0-dev-6' } ``` **Gradle Kotlin DSL:** ```kotlin repositories { maven("https://repo.kotlin.link") - mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap + maven("https://dl.bintray.com/hotkeytlt/maven") // required for a } dependencies { - implementation("space.kscience:kmath-complex:0.4.0-dev-1") + implementation("space.kscience:kmath-complex:0.3.0-dev-6") } ``` diff --git a/kmath-complex/build.gradle.kts b/kmath-complex/build.gradle.kts index 0611e9aae..43911e70d 100644 --- a/kmath-complex/build.gradle.kts +++ b/kmath-complex/build.gradle.kts @@ -1,55 +1,42 @@ +import ru.mipt.npm.gradle.Maturity + +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + plugins { - id("space.kscience.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } -kscience { - jvm() - js() - native() - - wasm{ - browser { - testTask { - useKarma { - this.webpackConfig.experiments.add("topLevelAwait") - useChromeHeadless() - useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm")) - } - } - } +kotlin.sourceSets { + all { + languageSettings.useExperimentalAnnotation("kscience.kmath.misc.UnstableKMathAPI") } - wasmTest{ + commonMain { dependencies { - implementation(kotlin("test")) + api(project(":kmath-core")) } } - - dependencies { - api(projects.kmathCore) - } - - testDependencies { - implementation(projects.testUtils) - } } readme { description = "Complex numbers and quaternions." - maturity = space.kscience.gradle.Maturity.PROTOTYPE + maturity = Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( id = "complex", + description = "Complex Numbers", ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt" - ) { - "Complex numbers operations" - } + ) feature( id = "quaternion", + description = "Quaternions", ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt" - ) { - "Quaternions and their composition" - } + ) } diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt index b5f1aabe7..8d626c17d 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt @@ -1,16 +1,19 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.complex -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.memory.MemoryReader import space.kscience.kmath.memory.MemorySpec import space.kscience.kmath.memory.MemoryWriter +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.MemoryBuffer +import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.structures.MutableMemoryBuffer import kotlin.math.* /** @@ -38,7 +41,7 @@ public val Complex.r: Double * An angle between vector represented by complex number and X axis. */ public val Complex.theta: Double - get() = atan2(im, re) + get() = atan(im / re) private val PI_DIV_2 = Complex(PI / 2, 0) @@ -46,25 +49,10 @@ private val PI_DIV_2 = Complex(PI / 2, 0) * A field of [Complex]. */ @OptIn(UnstableKMathAPI::class) -public object ComplexField : - ExtendedField, - Norm, - NumbersAddOps, +public object ComplexField : ExtendedField, Norm, NumbersAddOperations, ScaleOperations { - override val bufferFactory: MutableBufferFactory = MutableBufferFactory { size, init -> - MutableMemoryBuffer.create(Complex, size, init) - } - - override val zero: Complex = 0.0.toComplex() - override val one: Complex = 1.0.toComplex() - - override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null - - override fun binaryOperationFunction(operation: String): (left: Complex, right: Complex) -> Complex = - when (operation) { - PowerOperations.POW_OPERATION -> ComplexField::power - else -> super.binaryOperationFunction(operation) - } + public override val zero: Complex = 0.0.toComplex() + public override val one: Complex = 1.0.toComplex() /** * The imaginary unit. @@ -77,69 +65,63 @@ public object ComplexField : override fun scale(a: Complex, value: Double): Complex = Complex(a.re * value, a.im * value) - override fun add(left: Complex, right: Complex): Complex = Complex(left.re + right.re, left.im + right.im) -// override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble()) + public override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im) +// public override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble()) -// override fun Complex.minus(arg: Complex): Complex = Complex(re - arg.re, im - arg.im) + public override fun multiply(a: Complex, b: Complex): Complex = + Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re) - override fun multiply(left: Complex, right: Complex): Complex = - Complex(left.re * right.re - left.im * right.im, left.re * right.im + left.im * right.re) - - override fun divide(left: Complex, right: Complex): Complex = when { - abs(right.im) < abs(right.re) -> { - val wr = right.im / right.re - val wd = right.re + wr * right.im + public override fun divide(a: Complex, b: Complex): Complex = when { + abs(b.im) < abs(b.re) -> { + val wr = b.im / b.re + val wd = b.re + wr * b.im if (wd.isNaN() || wd == 0.0) throw ArithmeticException("Division by zero or infinity") else - Complex((left.re + left.im * wr) / wd, (left.im - left.re * wr) / wd) + Complex((a.re + a.im * wr) / wd, (a.im - a.re * wr) / wd) } - right.im == 0.0 -> throw ArithmeticException("Division by zero") + b.im == 0.0 -> throw ArithmeticException("Division by zero") else -> { - val wr = right.re / right.im - val wd = right.im + wr * right.re + val wr = b.re / b.im + val wd = b.im + wr * b.re if (wd.isNaN() || wd == 0.0) throw ArithmeticException("Division by zero or infinity") else - Complex((left.re * wr + left.im) / wd, (left.im * wr - left.re) / wd) + Complex((a.re * wr + a.im) / wd, (a.im * wr - a.re) / wd) } } override operator fun Complex.div(k: Number): Complex = Complex(re / k.toDouble(), im / k.toDouble()) - override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2.0 - override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2.0 + public override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2.0 + public override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2.0 - override fun tan(arg: Complex): Complex { + public override fun tan(arg: Complex): Complex { val e1 = exp(-i * arg) val e2 = exp(i * arg) return i * (e1 - e2) / (e1 + e2) } - override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg) - override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg) + public override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg) + public override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg) - override fun atan(arg: Complex): Complex { + public override fun atan(arg: Complex): Complex { val iArg = i * arg return i * (ln(1 - iArg) - ln(1 + iArg)) / 2 } - override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) { + public override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) arg.re.pow(pow.toDouble()).toComplex() - } else { + else exp(pow * ln(arg)) - } - public fun power(arg: Complex, pow: Complex): Complex = exp(pow * ln(arg)) + public override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) - - override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) - - override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re) + public override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re) /** * Adds complex number to real one. @@ -186,7 +168,9 @@ public object ComplexField : */ public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this) - override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) + public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) + + public override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null } /** @@ -195,27 +179,29 @@ public object ComplexField : * @property re The real part. * @property im The imaginary part. */ -public data class Complex(val re: Double, val im: Double) { +@OptIn(UnstableKMathAPI::class) +public data class Complex(val re: Double, val im: Double) : FieldElement { public constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble()) public constructor(re: Number) : this(re.toDouble(), 0.0) - override fun toString(): String = "($re + i * $im)" + public override val context: ComplexField get() = ComplexField + + public override fun toString(): String = "($re + i*$im)" public companion object : MemorySpec { - override val objectSize: Int + public override val objectSize: Int get() = 16 - override fun MemoryReader.read(offset: Int): Complex = + public override fun MemoryReader.read(offset: Int): Complex = Complex(readDouble(offset), readDouble(offset + 8)) - override fun MemoryWriter.write(offset: Int, value: Complex) { + public override fun MemoryWriter.write(offset: Int, value: Complex) { writeDouble(offset, value.re) writeDouble(offset + 8, value.im) } } } -public val Complex.Companion.algebra: ComplexField get() = ComplexField /** * Creates a complex number with real part equal to this real. diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt index 90a6b3253..2c783eda0 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt @@ -1,14 +1,17 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.complex -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.* +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.AlgebraND +import space.kscience.kmath.nd.BufferND +import space.kscience.kmath.nd.BufferedFieldND +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.NumbersAddOperations import space.kscience.kmath.structures.Buffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -18,65 +21,104 @@ import kotlin.contracts.contract * An optimized nd-field for complex numbers */ @OptIn(UnstableKMathAPI::class) -public sealed class ComplexFieldOpsND : BufferedFieldOpsND(ComplexField.bufferAlgebra), - ScaleOperations>, ExtendedFieldOps>, PowerOperations> { +public class ComplexFieldND( + shape: IntArray, +) : BufferedFieldND(shape, ComplexField, Buffer.Companion::complex), + NumbersAddOperations>, + ExtendedField> { - @OptIn(PerformancePitfall::class) - override fun StructureND.toBufferND(): BufferND = when (this) { - is BufferND -> this - else -> { - val indexer = indexerBuilder(shape) - BufferND(indexer, Buffer.complex(indexer.linearSize) { offset -> get(indexer.index(offset)) }) - } + public override val zero: BufferND by lazy { produce { zero } } + public override val one: BufferND by lazy { produce { one } } + + public override fun number(value: Number): BufferND { + val d = value.toComplex() // minimize conversions + return produce { d } } - //TODO do specialization +// +// @Suppress("OVERRIDE_BY_INLINE") +// override inline fun map( +// arg: AbstractNDBuffer, +// transform: DoubleField.(Double) -> Double, +// ): RealNDElement { +// check(arg) +// val array = RealBuffer(arg.strides.linearSize) { offset -> DoubleField.transform(arg.buffer[offset]) } +// return BufferedNDFieldElement(this, array) +// } +// +// @Suppress("OVERRIDE_BY_INLINE") +// override inline fun produce(initializer: DoubleField.(IntArray) -> Double): RealNDElement { +// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } +// return BufferedNDFieldElement(this, array) +// } +// +// @Suppress("OVERRIDE_BY_INLINE") +// override inline fun mapIndexed( +// arg: AbstractNDBuffer, +// transform: DoubleField.(index: IntArray, Double) -> Double, +// ): RealNDElement { +// check(arg) +// return BufferedNDFieldElement( +// this, +// RealBuffer(arg.strides.linearSize) { offset -> +// elementContext.transform( +// arg.strides.index(offset), +// arg.buffer[offset] +// ) +// }) +// } +// +// @Suppress("OVERRIDE_BY_INLINE") +// override inline fun combine( +// a: AbstractNDBuffer, +// b: AbstractNDBuffer, +// transform: DoubleField.(Double, Double) -> Double, +// ): RealNDElement { +// check(a, b) +// val buffer = RealBuffer(strides.linearSize) { offset -> +// elementContext.transform(a.buffer[offset], b.buffer[offset]) +// } +// return BufferedNDFieldElement(this, buffer) +// } - override fun scale(a: StructureND, value: Double): BufferND = - mapInline(a.toBufferND()) { it * value } + public override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } - override fun exp(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { exp(it) } - override fun ln(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { ln(it) } + public override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - override fun sin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sin(it) } - override fun cos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cos(it) } - override fun tan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tan(it) } - override fun asin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asin(it) } - override fun acos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acos(it) } - override fun atan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atan(it) } + public override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - override fun sinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sinh(it) } - override fun cosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cosh(it) } - override fun tanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tanh(it) } - override fun asinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asinh(it) } - override fun acosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acosh(it) } - override fun atanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atanh(it) } + public override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } + public override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } + public override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } + public override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } + public override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } + public override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } - override fun power(arg: StructureND, pow: Number): StructureND = - mapInline(arg.toBufferND()) { power(it,pow) } - - public companion object : ComplexFieldOpsND() + public override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } + public override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } + public override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } + public override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } + public override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } + public override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } } -@OptIn(UnstableKMathAPI::class) -public class ComplexFieldND(override val shape: ShapeND) : - ComplexFieldOpsND(), FieldND, - NumbersAddOps> { - override fun number(value: Number): BufferND { - val d = value.toDouble() // minimize conversions - return structureND(shape) { d.toComplex() } - } +/** + * Fast element production using function inlining + */ +public inline fun BufferedFieldND.produceInline(initializer: ComplexField.(Int) -> Complex): BufferND { + contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) } + val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) } + return BufferND(strides, buffer) } -public val ComplexField.ndAlgebra: ComplexFieldOpsND get() = ComplexFieldOpsND -public fun ComplexField.ndAlgebra(vararg shape: Int): ComplexFieldND = ComplexFieldND(ShapeND(shape)) +public fun AlgebraND.Companion.complex(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape) /** * Produce a context for n-dimensional operations inside this real field */ -public inline fun ComplexField.withNdAlgebra(vararg shape: Int, action: ComplexFieldND.() -> R): R { +public inline fun ComplexField.nd(vararg shape: Int, action: ComplexFieldND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return ComplexFieldND(ShapeND(shape)).action() + return ComplexFieldND(shape).action() } diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt index d4259c4dc..382b5cc05 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -1,14 +1,14 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.complex -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.memory.MemoryReader import space.kscience.kmath.memory.MemorySpec import space.kscience.kmath.memory.MemoryWriter +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MemoryBuffer @@ -16,163 +16,76 @@ import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableMemoryBuffer import kotlin.math.* -/** - * Represents `double`-based quaternion. - * - * @property w The first component. - * @property x The second component. - * @property y The third component. - * @property z The fourth component. - */ -public class Quaternion( - public val w: Double, - public val x: Double, - public val y: Double, - public val z: Double, -) : Buffer { - init { - require(!w.isNaN()) { "w-component of quaternion is not-a-number" } - require(!x.isNaN()) { "x-component of quaternion is not-a-number" } - require(!y.isNaN()) { "y-component of quaternion is not-a-number" } - require(!z.isNaN()) { "z-component of quaternion is not-a-number" } - } - - /** - * Returns a string representation of this quaternion. - */ - override fun toString(): String = "($w + $x * i + $y * j + $z * k)" - - override val size: Int get() = 4 - - override fun get(index: Int): Double = when (index) { - 0 -> w - 1 -> x - 2 -> y - 3 -> z - else -> error("Index $index out of bounds [0,3]") - } - - override fun iterator(): Iterator = listOf(w, x, y, z).iterator() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as Quaternion - - if (w != other.w) return false - if (x != other.x) return false - if (y != other.y) return false - if (z != other.z) return false - - return true - } - - override fun hashCode(): Int { - var result = w.hashCode() - result = 31 * result + x.hashCode() - result = 31 * result + y.hashCode() - result = 31 * result + z.hashCode() - return result - } - - public companion object : MemorySpec { - override val objectSize: Int get() = 32 - - override fun MemoryReader.read(offset: Int): Quaternion = Quaternion( - readDouble(offset), - readDouble(offset + 8), - readDouble(offset + 16), - readDouble(offset + 24) - ) - - override fun MemoryWriter.write(offset: Int, value: Quaternion) { - writeDouble(offset, value.w) - writeDouble(offset + 8, value.x) - writeDouble(offset + 16, value.y) - writeDouble(offset + 24, value.z) - } - } -} - -public fun Quaternion(w: Number, x: Number = 0.0, y: Number = 0.0, z: Number = 0.0): Quaternion = Quaternion( - w.toDouble(), - x.toDouble(), - y.toDouble(), - z.toDouble(), -) - /** * This quaternion's conjugate. */ public val Quaternion.conjugate: Quaternion - get() = Quaternion(w, -x, -y, -z) + get() = QuaternionField { z - x * i - y * j - z * k } /** * This quaternion's reciprocal. */ public val Quaternion.reciprocal: Quaternion get() { - val norm2 = (w * w + x * x + y * y + z * z) - return Quaternion(w / norm2, -x / norm2, -y / norm2, -z / norm2) + val n = QuaternionField { norm(this@reciprocal) } + return conjugate / (n * n) } - -//TODO consider adding a-priory normalized quaternions /** - * Produce a normalized version of this quaternion + * Absolute value of the quaternion. */ -public fun Quaternion.normalized(): Quaternion = with(QuaternionField){ this@normalized / norm(this@normalized) } +public val Quaternion.r: Double + get() = sqrt(w * w + x * x + y * y + z * z) /** * A field of [Quaternion]. */ @OptIn(UnstableKMathAPI::class) -public object QuaternionField : Field, Norm, PowerOperations, - ExponentialOperations, NumbersAddOps, ScaleOperations { - override val zero: Quaternion = Quaternion(0.0) - override val one: Quaternion = Quaternion(1.0) +public object QuaternionField : Field, Norm, PowerOperations, + ExponentialOperations, NumbersAddOperations, ScaleOperations { + override val zero: Quaternion = 0.toQuaternion() + override val one: Quaternion = 1.toQuaternion() /** * The `i` quaternion unit. */ - public val i: Quaternion = Quaternion(0.0, 1.0, 0.0, 0.0) + public val i: Quaternion = Quaternion(0, 1) /** * The `j` quaternion unit. */ - public val j: Quaternion = Quaternion(0.0, 0.0, 1.0, 0.0) + public val j: Quaternion = Quaternion(0, 0, 1) /** * The `k` quaternion unit. */ - public val k: Quaternion = Quaternion(0.0, 0.0, 0.0, 1.0) + public val k: Quaternion = Quaternion(0, 0, 0, 1) - override fun add(left: Quaternion, right: Quaternion): Quaternion = - Quaternion(left.w + right.w, left.x + right.x, left.y + right.y, left.z + right.z) + public override fun add(a: Quaternion, b: Quaternion): Quaternion = + Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z) - override fun scale(a: Quaternion, value: Double): Quaternion = + public override fun scale(a: Quaternion, value: Double): Quaternion = Quaternion(a.w * value, a.x * value, a.y * value, a.z * value) - override fun multiply(left: Quaternion, right: Quaternion): Quaternion = Quaternion( - left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z, - left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y, - left.w * right.y - left.x * right.z + left.y * right.w + left.z * right.x, - left.w * right.z + left.x * right.y - left.y * right.x + left.z * right.w, + public override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion( + a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, + a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, + a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x, + a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w, ) - override fun divide(left: Quaternion, right: Quaternion): Quaternion { - val s = right.w * right.w + right.x * right.x + right.y * right.y + right.z * right.z + public override fun divide(a: Quaternion, b: Quaternion): Quaternion { + val s = b.w * b.w + b.x * b.x + b.y * b.y + b.z * b.z return Quaternion( - (right.w * left.w + right.x * left.x + right.y * left.y + right.z * left.z) / s, - (right.w * left.x - right.x * left.w - right.y * left.z + right.z * left.y) / s, - (right.w * left.y + right.x * left.z - right.y * left.w - right.z * left.x) / s, - (right.w * left.z - right.x * left.y + right.y * left.x - right.z * left.w) / s, + (b.w * a.w + b.x * a.x + b.y * a.y + b.z * a.z) / s, + (b.w * a.x - b.x * a.w - b.y * a.z + b.z * a.y) / s, + (b.w * a.y + b.x * a.z - b.y * a.w - b.z * a.x) / s, + (b.w * a.z - b.x * a.y + b.y * a.x - b.z * a.w) / s, ) } - override fun power(arg: Quaternion, pow: Number): Quaternion { + public override fun power(arg: Quaternion, pow: Number): Quaternion { if (pow is Int) return pwr(arg, pow) if (floor(pow.toDouble()) == pow.toDouble()) return pwr(arg, pow.toInt()) return exp(pow * ln(arg)) @@ -216,23 +129,23 @@ public object QuaternionField : Field, Norm, Pow return Quaternion(a2 * a2 - 6 * a2 * n1 + n1 * n1, x.x * n2, x.y * n2, x.z * n2) } - override fun exp(arg: Quaternion): Quaternion { + public override fun exp(arg: Quaternion): Quaternion { val un = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z - if (un == 0.0) return Quaternion(exp(arg.w)) + if (un == 0.0) return exp(arg.w).toQuaternion() val n1 = sqrt(un) val ea = exp(arg.w) val n2 = ea * sin(n1) / n1 return Quaternion(ea * cos(n1), n2 * arg.x, n2 * arg.y, n2 * arg.z) } - override fun ln(arg: Quaternion): Quaternion { + public override fun ln(arg: Quaternion): Quaternion { val nu2 = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z if (nu2 == 0.0) return if (arg.w > 0) Quaternion(ln(arg.w), 0, 0, 0) else { - val l = ComplexField { ln(arg.w.toComplex()) } + val l = ComplexField { ComplexField.ln(arg.w.toComplex()) } Quaternion(l.re, l.im, 0, 0) } @@ -243,43 +156,109 @@ public object QuaternionField : Field, Norm, Pow return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z) } - override operator fun Number.plus(other: Quaternion): Quaternion = - Quaternion(toDouble() + other.w, other.x, other.y, other.z) + public override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z) - override operator fun Number.minus(other: Quaternion): Quaternion = - Quaternion(toDouble() - other.w, -other.x, -other.y, -other.z) + public override operator fun Number.minus(b: Quaternion): Quaternion = + Quaternion(toDouble() - b.w, -b.x, -b.y, -b.z) - override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z) - override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z) + public override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z) + public override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.toDouble(), x, y, z) - override operator fun Number.times(arg: Quaternion): Quaternion = - Quaternion(toDouble() * arg.w, toDouble() * arg.x, toDouble() * arg.y, toDouble() * arg.z) + public override operator fun Number.times(b: Quaternion): Quaternion = + Quaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z) - override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) - override fun norm(arg: Quaternion): Double = sqrt( - arg.w.pow(2) + - arg.x.pow(2) + - arg.y.pow(2) + - arg.z.pow(2) - ) + public override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) + public override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) - override fun bindSymbolOrNull(value: String): Quaternion? = when (value) { + public override fun bindSymbolOrNull(value: String): Quaternion? = when (value) { "i" -> i "j" -> j "k" -> k else -> null } - override fun number(value: Number): Quaternion = Quaternion(value) + override fun number(value: Number): Quaternion = value.toQuaternion() - override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 - override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0 - override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) - override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg) - override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one))) - override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0 + public override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 + public override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0 + public override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) + public override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg) + public override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one))) + public override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0 } +/** + * Represents `double`-based quaternion. + * + * @property w The first component. + * @property x The second component. + * @property y The third component. + * @property z The fourth component. + */ +@OptIn(UnstableKMathAPI::class) +public data class Quaternion( + val w: Double, val x: Double, val y: Double, val z: Double, +) : FieldElement { + public constructor(w: Number, x: Number, y: Number, z: Number) : this( + w.toDouble(), + x.toDouble(), + y.toDouble(), + z.toDouble(), + ) + + public constructor(w: Number, x: Number, y: Number) : this(w.toDouble(), x.toDouble(), y.toDouble(), 0.0) + public constructor(w: Number, x: Number) : this(w.toDouble(), x.toDouble(), 0.0, 0.0) + public constructor(w: Number) : this(w.toDouble(), 0.0, 0.0, 0.0) + public constructor(wx: Complex, yz: Complex) : this(wx.re, wx.im, yz.re, yz.im) + public constructor(wx: Complex) : this(wx.re, wx.im, 0, 0) + + init { + require(!w.isNaN()) { "w-component of quaternion is not-a-number" } + require(!x.isNaN()) { "x-component of quaternion is not-a-number" } + require(!y.isNaN()) { "x-component of quaternion is not-a-number" } + require(!z.isNaN()) { "x-component of quaternion is not-a-number" } + } + + public override val context: QuaternionField get() = QuaternionField + + /** + * Returns a string representation of this quaternion. + */ + public override fun toString(): String = "($w + $x * i + $y * j + $z * k)" + + public companion object : MemorySpec { + public override val objectSize: Int + get() = 32 + + public override fun MemoryReader.read(offset: Int): Quaternion = + Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24)) + + public override fun MemoryWriter.write(offset: Int, value: Quaternion) { + writeDouble(offset, value.w) + writeDouble(offset + 8, value.x) + writeDouble(offset + 16, value.y) + writeDouble(offset + 24, value.z) + } + } +} + +/** + * Creates a quaternion with real part equal to this real. + * + * @receiver the real part. + * @return a new quaternion. + */ +public fun Number.toQuaternion(): Quaternion = Quaternion(this) + +/** + * Creates a quaternion with `w`-component equal to `re`-component of given complex and `x`-component equal to + * `im`-component of given complex. + * + * @receiver the complex number. + * @return a new quaternion. + */ +public fun Complex.toQuaternion(): Quaternion = Quaternion(this) + /** * Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the * specified [init] function. diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt index ca3f8f43f..17a077ea7 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt index e11f1c1ea..cbaaa815b 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt index 1a35d1dd8..7ad7f883d 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt index 767406e0b..e023fcb81 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,7 +7,7 @@ package space.kscience.kmath.complex import space.kscience.kmath.expressions.FunctionalExpressionField import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.misc.symbol import space.kscience.kmath.operations.bindSymbol import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt similarity index 82% rename from kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt rename to kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt index fd0fd46a7..6784f3516 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt @@ -1,28 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.complex import space.kscience.kmath.operations.invoke -import space.kscience.kmath.testutils.assertBufferEquals import kotlin.test.Test import kotlin.test.assertEquals -internal class QuaternionTest { - - @Test - fun testNorm() { - assertEquals(2.0, QuaternionField.norm(Quaternion(1.0, 1.0, 1.0, 1.0))) - } - - @Test - fun testInverse() = QuaternionField { - val q = Quaternion(1.0, 2.0, -3.0, 4.0) - assertBufferEquals(one, q * q.reciprocal, 1e-4) - } - +internal class QuaternionFieldTest { @Test fun testAddition() { assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(16, 16) + Quaternion(26, 26) }) diff --git a/kmath-core/README.md b/kmath-core/README.md index b58105d2f..b83fb13d0 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -10,32 +10,34 @@ The core interfaces of KMath. objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high performance calculations to code generation. - [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains - - [autodiff](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation + - [autodif](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.4.0-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-6`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } - mavenCentral() + maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap } dependencies { - implementation 'space.kscience:kmath-core:0.4.0-dev-1' + implementation 'space.kscience:kmath-core:0.3.0-dev-6' } ``` **Gradle Kotlin DSL:** ```kotlin repositories { maven("https://repo.kotlin.link") - mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap + maven("https://dl.bintray.com/hotkeytlt/maven") // required for a } dependencies { - implementation("space.kscience:kmath-core:0.4.0-dev-1") + implementation("space.kscience:kmath-core:0.3.0-dev-6") } ``` diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 42d8277bd..6b300123c 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -1,14 +1,8 @@ public final class space/kscience/kmath/data/ColumnarDataKt { } -public final class space/kscience/kmath/data/XYColumnarData$Companion { -} - public final class space/kscience/kmath/data/XYColumnarDataKt { -} - -public final class space/kscience/kmath/data/XYErrorColumnarData$Companion { - public final fun of (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/data/XYErrorColumnarData; + public static synthetic fun asXYData$default (Lspace/kscience/kmath/nd/Structure2D;IIILjava/lang/Object;)Lspace/kscience/kmath/data/XYColumnarData; } public abstract interface class space/kscience/kmath/domains/Domain { @@ -16,11 +10,8 @@ public abstract interface class space/kscience/kmath/domains/Domain { public abstract fun getDimension ()I } -public final class space/kscience/kmath/domains/Domain1DKt { -} - public abstract interface class space/kscience/kmath/expressions/AutoDiffProcessor { - public abstract fun differentiate (Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/DifferentiableExpression; + public abstract fun process (Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/DifferentiableExpression; } public class space/kscience/kmath/expressions/AutoDiffValue { @@ -28,33 +19,14 @@ public class space/kscience/kmath/expressions/AutoDiffValue { public final fun getValue ()Ljava/lang/Object; } -public final class space/kscience/kmath/expressions/DSAlgebraKt { -} - -public final class space/kscience/kmath/expressions/DSCompiler { - public final fun getAlgebra ()Lspace/kscience/kmath/operations/Algebra; - public final fun getFreeParameters ()I - public final fun getOrder ()I - public final fun getPartialDerivativeIndex ([I)I - public final fun getPartialDerivativeOrders (I)[I - public final fun getSize ()I - public final fun getSizes ()[[I -} - public final class space/kscience/kmath/expressions/DerivationResult { public fun (Ljava/lang/Object;Ljava/util/Map;Lspace/kscience/kmath/operations/Field;)V - public final fun derivative (Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object; + public final fun derivative (Lspace/kscience/kmath/misc/Symbol;)Ljava/lang/Object; public final fun div ()Ljava/lang/Object; public final fun getContext ()Lspace/kscience/kmath/operations/Field; public final fun getValue ()Ljava/lang/Object; } -public final class space/kscience/kmath/expressions/DiffExpressionWithDefault : space/kscience/kmath/expressions/DifferentiableExpression { - public fun (Lspace/kscience/kmath/expressions/DifferentiableExpression;Ljava/util/Map;)V - public fun derivativeOrNull (Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression; - public fun invoke (Ljava/util/Map;)Ljava/lang/Object; -} - public abstract interface class space/kscience/kmath/expressions/DifferentiableExpression : space/kscience/kmath/expressions/Expression { public abstract fun derivativeOrNull (Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression; } @@ -62,13 +34,7 @@ public abstract interface class space/kscience/kmath/expressions/DifferentiableE public final class space/kscience/kmath/expressions/DifferentiableExpressionKt { public static final fun derivative (Lspace/kscience/kmath/expressions/DifferentiableExpression;Ljava/lang/String;)Lspace/kscience/kmath/expressions/Expression; public static final fun derivative (Lspace/kscience/kmath/expressions/DifferentiableExpression;Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression; - public static final fun derivative (Lspace/kscience/kmath/expressions/DifferentiableExpression;[Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/expressions/Expression; - public static final fun derivative (Lspace/kscience/kmath/expressions/SpecialDifferentiableExpression;Ljava/lang/String;)Lspace/kscience/kmath/expressions/Expression; - public static final fun derivative (Lspace/kscience/kmath/expressions/SpecialDifferentiableExpression;Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression; - public static final fun derivative (Lspace/kscience/kmath/expressions/SpecialDifferentiableExpression;[Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/expressions/Expression; -} - -public final class space/kscience/kmath/expressions/DoubleExpression$Companion { + public static final fun derivative (Lspace/kscience/kmath/expressions/DifferentiableExpression;[Lspace/kscience/kmath/misc/Symbol;)Lspace/kscience/kmath/expressions/Expression; } public abstract interface class space/kscience/kmath/expressions/Expression { @@ -79,27 +45,24 @@ public abstract interface class space/kscience/kmath/expressions/ExpressionAlgeb public abstract fun const (Ljava/lang/Object;)Ljava/lang/Object; } +public final class space/kscience/kmath/expressions/ExpressionBuildersKt { + public static final fun extendedFieldExpression (Lspace/kscience/kmath/operations/ExtendedField;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; + public static final fun fieldExpression (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; + public static final fun ringExpression (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; + public static final fun spaceExpression (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; +} + public final class space/kscience/kmath/expressions/ExpressionKt { + public static final fun binding (Lspace/kscience/kmath/expressions/ExpressionAlgebra;)Lkotlin/properties/ReadOnlyProperty; public static final fun callByString (Lspace/kscience/kmath/expressions/Expression;[Lkotlin/Pair;)Ljava/lang/Object; public static final fun callBySymbol (Lspace/kscience/kmath/expressions/Expression;[Lkotlin/Pair;)Ljava/lang/Object; - public static final fun getBinding (Lspace/kscience/kmath/expressions/ExpressionAlgebra;)Lkotlin/properties/ReadOnlyProperty; public static final fun invoke (Lspace/kscience/kmath/expressions/Expression;)Ljava/lang/Object; } -public final class space/kscience/kmath/expressions/ExpressionWithDefault : space/kscience/kmath/expressions/Expression { - public fun (Lspace/kscience/kmath/expressions/Expression;Ljava/util/Map;)V - public fun invoke (Ljava/util/Map;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/expressions/ExpressionWithDefaultKt { - public static final fun withDefaultArgs (Lspace/kscience/kmath/expressions/DifferentiableExpression;Ljava/util/Map;)Lspace/kscience/kmath/expressions/DiffExpressionWithDefault; - public static final fun withDefaultArgs (Lspace/kscience/kmath/expressions/Expression;Ljava/util/Map;)Lspace/kscience/kmath/expressions/ExpressionWithDefault; -} - public abstract class space/kscience/kmath/expressions/FirstDerivativeExpression : space/kscience/kmath/expressions/DifferentiableExpression { public fun ()V public final fun derivativeOrNull (Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression; - public abstract fun derivativeOrNull (Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/expressions/Expression; + public abstract fun derivativeOrNull (Lspace/kscience/kmath/misc/Symbol;)Lspace/kscience/kmath/expressions/Expression; } public abstract class space/kscience/kmath/expressions/FunctionalExpressionAlgebra : space/kscience/kmath/expressions/ExpressionAlgebra { @@ -114,11 +77,10 @@ public abstract class space/kscience/kmath/expressions/FunctionalExpressionAlgeb } public final class space/kscience/kmath/expressions/FunctionalExpressionAlgebraKt { - public static final fun expression (Lspace/kscience/kmath/operations/DoubleField;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; public static final fun expressionInExtendedField (Lspace/kscience/kmath/operations/ExtendedField;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; public static final fun expressionInField (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; - public static final fun expressionInGroup (Lspace/kscience/kmath/operations/Group;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; public static final fun expressionInRing (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; + public static final fun expressionInSpace (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; } public class space/kscience/kmath/expressions/FunctionalExpressionExtendedField : space/kscience/kmath/expressions/FunctionalExpressionField, space/kscience/kmath/operations/ExtendedField { @@ -130,6 +92,8 @@ public class space/kscience/kmath/expressions/FunctionalExpressionExtendedField public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; public fun atan (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; + public synthetic fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; + public fun bindSymbol (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Expression; public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; public fun cos (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; @@ -189,13 +153,7 @@ public class space/kscience/kmath/expressions/FunctionalExpressionRing : space/k public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; } -public final class space/kscience/kmath/expressions/IntExpression$Companion { -} - -public final class space/kscience/kmath/expressions/LongExpression$Companion { -} - -public abstract interface class space/kscience/kmath/expressions/MST { +public abstract class space/kscience/kmath/expressions/MST { } public final class space/kscience/kmath/expressions/MST$Binary : space/kscience/kmath/expressions/MST { @@ -224,6 +182,17 @@ public final class space/kscience/kmath/expressions/MST$Numeric : space/kscience public fun toString ()Ljava/lang/String; } +public final class space/kscience/kmath/expressions/MST$Symbolic : space/kscience/kmath/expressions/MST { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lspace/kscience/kmath/expressions/MST$Symbolic; + public static synthetic fun copy$default (Lspace/kscience/kmath/expressions/MST$Symbolic;Ljava/lang/String;ILjava/lang/Object;)Lspace/kscience/kmath/expressions/MST$Symbolic; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class space/kscience/kmath/expressions/MST$Unary : space/kscience/kmath/expressions/MST { public fun (Ljava/lang/String;Lspace/kscience/kmath/expressions/MST;)V public final fun component1 ()Ljava/lang/String; @@ -238,11 +207,24 @@ public final class space/kscience/kmath/expressions/MST$Unary : space/kscience/k } public final class space/kscience/kmath/expressions/MSTKt { + public static final fun evaluate (Lspace/kscience/kmath/operations/Algebra;Lspace/kscience/kmath/expressions/MST;)Ljava/lang/Object; public static final fun interpret (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/operations/Algebra;Ljava/util/Map;)Ljava/lang/Object; public static final fun interpret (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/operations/Algebra;[Lkotlin/Pair;)Ljava/lang/Object; public static final fun toExpression (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/operations/Algebra;)Lspace/kscience/kmath/expressions/Expression; } +public final class space/kscience/kmath/expressions/MstAlgebra : space/kscience/kmath/operations/NumericAlgebra { + public static final field INSTANCE Lspace/kscience/kmath/expressions/MstAlgebra; + public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; + public synthetic fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; + public fun bindSymbol (Ljava/lang/String;)Lspace/kscience/kmath/expressions/MST$Symbolic; + public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; + public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/MST$Symbolic; + public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; + public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric; + public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; +} + public final class space/kscience/kmath/expressions/MstExtendedField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumericAlgebra { public static final field INSTANCE Lspace/kscience/kmath/expressions/MstExtendedField; public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; @@ -261,7 +243,7 @@ public final class space/kscience/kmath/expressions/MstExtendedField : space/ksc public fun atanh (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; + public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/MST$Symbolic; public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; public fun cos (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; @@ -290,8 +272,6 @@ public final class space/kscience/kmath/expressions/MstExtendedField : space/ksc public fun sin (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; public fun sinh (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object; - public fun sqrt (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST; public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; public fun tan (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; @@ -303,13 +283,13 @@ public final class space/kscience/kmath/expressions/MstExtendedField : space/ksc public fun unaryPlus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; } -public final class space/kscience/kmath/expressions/MstField : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumbersAddOps, space/kscience/kmath/operations/ScaleOperations { +public final class space/kscience/kmath/expressions/MstField : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/ScaleOperations { public static final field INSTANCE Lspace/kscience/kmath/expressions/MstField; public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun add (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; + public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/MST$Symbolic; public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun divide (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; public synthetic fun getOne ()Ljava/lang/Object; @@ -337,7 +317,7 @@ public final class space/kscience/kmath/expressions/MstGroup : space/kscience/km public fun add (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; + public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/MST$Symbolic; public synthetic fun getZero ()Ljava/lang/Object; public fun getZero ()Lspace/kscience/kmath/expressions/MST$Numeric; public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; @@ -353,25 +333,13 @@ public final class space/kscience/kmath/expressions/MstGroup : space/kscience/km public fun unaryPlus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; } -public final class space/kscience/kmath/expressions/MstNumericAlgebra : space/kscience/kmath/operations/NumericAlgebra { - public static final field INSTANCE Lspace/kscience/kmath/expressions/MstNumericAlgebra; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbol (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; - public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public final class space/kscience/kmath/expressions/MstRing : space/kscience/kmath/operations/NumbersAddOps, space/kscience/kmath/operations/Ring, space/kscience/kmath/operations/ScaleOperations { +public final class space/kscience/kmath/expressions/MstRing : space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/Ring, space/kscience/kmath/operations/ScaleOperations { public static final field INSTANCE Lspace/kscience/kmath/expressions/MstRing; public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun add (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; + public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/MST$Symbolic; public synthetic fun getOne ()Ljava/lang/Object; public fun getOne ()Lspace/kscience/kmath/expressions/MST$Numeric; public synthetic fun getZero ()Ljava/lang/Object; @@ -391,38 +359,9 @@ public final class space/kscience/kmath/expressions/MstRing : space/kscience/kma public fun unaryPlus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; } -public final class space/kscience/kmath/expressions/NamedMatrix : space/kscience/kmath/nd/Structure2D { - public static final field Companion Lspace/kscience/kmath/expressions/NamedMatrix$Companion; - public fun (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/expressions/SymbolIndexer;)V - public fun elements ()Lkotlin/sequences/Sequence; - public fun get (II)Ljava/lang/Object; - public final fun get (Lspace/kscience/kmath/expressions/Symbol;Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object; - public fun get ([I)Ljava/lang/Object; - public fun getColNum ()I - public fun getColumns ()Ljava/util/List; - public fun getDimension ()I - public synthetic fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object; - public fun getFeature (Lkotlin/reflect/KClass;)Lspace/kscience/kmath/nd/StructureFeature; - public final fun getIndexer ()Lspace/kscience/kmath/expressions/SymbolIndexer; - public fun getIndices ()Lspace/kscience/kmath/nd/ShapeIndexer; - public fun getRowNum ()I - public fun getRows ()Ljava/util/List; - public fun getShape-IIYLAfE ()[I - public final fun getValues ()Lspace/kscience/kmath/nd/Structure2D; -} - -public final class space/kscience/kmath/expressions/NamedMatrix$Companion { - public final fun toStringWithSymbols (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/expressions/SymbolIndexer;)Ljava/lang/String; -} - -public final class space/kscience/kmath/expressions/NamedMatrixKt { - public static final fun named (Lspace/kscience/kmath/nd/Structure2D;Ljava/util/List;)Lspace/kscience/kmath/expressions/NamedMatrix; - public static final fun named (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/expressions/SymbolIndexer;)Lspace/kscience/kmath/expressions/NamedMatrix; -} - public final class space/kscience/kmath/expressions/SimpleAutoDiffExpression : space/kscience/kmath/expressions/FirstDerivativeExpression { public fun (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function1;)V - public fun derivativeOrNull (Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/expressions/Expression; + public fun derivativeOrNull (Lspace/kscience/kmath/misc/Symbol;)Lspace/kscience/kmath/expressions/Expression; public final fun getField ()Lspace/kscience/kmath/operations/Field; public final fun getFunction ()Lkotlin/jvm/functions/Function1; public fun invoke (Ljava/util/Map;)Ljava/lang/Object; @@ -442,6 +381,8 @@ public final class space/kscience/kmath/expressions/SimpleAutoDiffExtendedField public fun atan (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; public fun atanh (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; + public synthetic fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; + public fun bindSymbol (Ljava/lang/String;)Lspace/kscience/kmath/expressions/AutoDiffValue; public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; public fun cos (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; @@ -470,7 +411,7 @@ public final class space/kscience/kmath/expressions/SimpleAutoDiffExtendedField public fun tanh (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; } -public class space/kscience/kmath/expressions/SimpleAutoDiffField : space/kscience/kmath/expressions/ExpressionAlgebra, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumbersAddOps { +public class space/kscience/kmath/expressions/SimpleAutoDiffField : space/kscience/kmath/expressions/ExpressionAlgebra, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumbersAddOperations { public fun (Lspace/kscience/kmath/operations/Field;Ljava/util/Map;)V public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun add (Lspace/kscience/kmath/expressions/AutoDiffValue;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; @@ -478,6 +419,7 @@ public class space/kscience/kmath/expressions/SimpleAutoDiffField : space/kscien public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/AutoDiffValue; public synthetic fun const (Ljava/lang/Object;)Ljava/lang/Object; public fun const (Ljava/lang/Object;)Lspace/kscience/kmath/expressions/AutoDiffValue; + public final fun const (Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/AutoDiffValue; public final fun derive (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun divide (Lspace/kscience/kmath/expressions/AutoDiffValue;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; @@ -505,11 +447,10 @@ public final class space/kscience/kmath/expressions/SimpleAutoDiffKt { public static final fun asinh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; public static final fun atan (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; public static final fun atanh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun const (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/AutoDiffValue; public static final fun cos (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; public static final fun cosh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; public static final fun exp (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun grad (Lspace/kscience/kmath/expressions/DerivationResult;[Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/structures/Buffer; + public static final fun grad (Lspace/kscience/kmath/expressions/DerivationResult;[Lspace/kscience/kmath/misc/Symbol;)Lspace/kscience/kmath/structures/Buffer; public static final fun ln (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; public static final fun pow (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;D)Lspace/kscience/kmath/expressions/AutoDiffValue; public static final fun pow (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;I)Lspace/kscience/kmath/expressions/AutoDiffValue; @@ -525,38 +466,11 @@ public final class space/kscience/kmath/expressions/SimpleAutoDiffKt { public static final fun tanh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; } -public abstract interface class space/kscience/kmath/expressions/SpecialDifferentiableExpression : space/kscience/kmath/expressions/DifferentiableExpression { - public abstract fun derivativeOrNull (Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression; -} - -public abstract interface class space/kscience/kmath/expressions/Symbol : space/kscience/kmath/expressions/MST { - public static final field Companion Lspace/kscience/kmath/expressions/Symbol$Companion; - public abstract fun getIdentity ()Ljava/lang/String; -} - -public final class space/kscience/kmath/expressions/Symbol$Companion { - public final fun getX ()Lspace/kscience/kmath/expressions/Symbol; - public final fun getXError ()Lspace/kscience/kmath/expressions/Symbol; - public final fun getY ()Lspace/kscience/kmath/expressions/Symbol; - public final fun getYError ()Lspace/kscience/kmath/expressions/Symbol; - public final fun getZ ()Lspace/kscience/kmath/expressions/Symbol; - public final fun getZError ()Lspace/kscience/kmath/expressions/Symbol; -} - public final class space/kscience/kmath/expressions/SymbolIndexerKt { } -public final class space/kscience/kmath/expressions/SymbolKt { - public static final fun Symbol (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; - public static final fun get (Ljava/util/Map;Ljava/lang/String;)Ljava/lang/Object; - public static final fun get (Ljava/util/Map;Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object; - public static final fun getSymbol ()Lkotlin/properties/ReadOnlyProperty; - public static final fun set (Ljava/util/Map;Ljava/lang/String;Ljava/lang/Object;)V - public static final fun set (Ljava/util/Map;Lspace/kscience/kmath/expressions/Symbol;Ljava/lang/Object;)V -} - public final class space/kscience/kmath/linear/BufferedLinearSpace : space/kscience/kmath/linear/LinearSpace { - public fun (Lspace/kscience/kmath/operations/BufferAlgebra;)V + public fun (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;)V public fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D; public fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer; public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; @@ -568,10 +482,6 @@ public final class space/kscience/kmath/linear/BufferedLinearSpace : space/kscie public fun unaryMinus (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; } -public final class space/kscience/kmath/linear/BufferedLinearSpaceKt { - public static final fun getLinearSpace (Lspace/kscience/kmath/operations/Ring;)Lspace/kscience/kmath/linear/BufferedLinearSpace; -} - public abstract interface class space/kscience/kmath/linear/CholeskyDecompositionFeature : space/kscience/kmath/linear/MatrixFeature { public abstract fun getL ()Lspace/kscience/kmath/nd/Structure2D; } @@ -587,36 +497,6 @@ public abstract interface class space/kscience/kmath/linear/DiagonalFeature : sp public final class space/kscience/kmath/linear/DiagonalFeature$Companion : space/kscience/kmath/linear/DiagonalFeature { } -public final class space/kscience/kmath/linear/DoubleLinearSpace : space/kscience/kmath/linear/LinearSpace { - public static final field INSTANCE Lspace/kscience/kmath/linear/DoubleLinearSpace; - public fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D; - public synthetic fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer; - public fun buildVector-CZ9oacQ (ILkotlin/jvm/functions/Function2;)[D - public final fun div-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;D)[D - public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public synthetic fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun dot-CZ9oacQ (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)[D - public fun getElementAlgebra ()Lspace/kscience/kmath/operations/DoubleField; - public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Ring; - public fun minus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public synthetic fun minus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun minus-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public synthetic fun plus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun plus-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun times (Ljava/lang/Object;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun times (Lspace/kscience/kmath/nd/Structure2D;D)Lspace/kscience/kmath/nd/Structure2D; - public synthetic fun times (Lspace/kscience/kmath/nd/Structure2D;Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D; - public synthetic fun times (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;)Lspace/kscience/kmath/structures/Buffer; - public fun times-CZ9oacQ (DLspace/kscience/kmath/structures/Buffer;)[D - public fun times-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;D)[D - public fun unaryMinus (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; -} - -public final class space/kscience/kmath/linear/DoubleLinearSpaceKt { - public static final fun getLinearSpace (Lspace/kscience/kmath/operations/DoubleField;)Lspace/kscience/kmath/linear/DoubleLinearSpace; -} - public abstract interface class space/kscience/kmath/linear/InverseMatrixFeature : space/kscience/kmath/linear/MatrixFeature { public abstract fun getInverse ()Lspace/kscience/kmath/nd/Structure2D; } @@ -625,17 +505,17 @@ public final class space/kscience/kmath/linear/LFeature : space/kscience/kmath/l public static final field INSTANCE Lspace/kscience/kmath/linear/LFeature; } -public abstract interface class space/kscience/kmath/linear/LUDecompositionFeature : space/kscience/kmath/linear/MatrixFeature { - public abstract fun getL ()Lspace/kscience/kmath/nd/Structure2D; - public abstract fun getU ()Lspace/kscience/kmath/nd/Structure2D; -} - public abstract interface class space/kscience/kmath/linear/LinearSolver { public abstract fun inverse (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; public abstract fun solve (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; public fun solve (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; } +public final class space/kscience/kmath/linear/LinearSolverKt { + public static final fun asMatrix (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/linear/VirtualMatrix; + public static final fun asVector (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/structures/Buffer; +} + public abstract interface class space/kscience/kmath/linear/LinearSpace { public static final field Companion Lspace/kscience/kmath/linear/LinearSpace$Companion; public abstract fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D; @@ -656,12 +536,12 @@ public abstract interface class space/kscience/kmath/linear/LinearSpace { } public final class space/kscience/kmath/linear/LinearSpace$Companion { - public final fun buffered (Lspace/kscience/kmath/operations/Ring;)Lspace/kscience/kmath/linear/LinearSpace; + public final fun buffered (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/linear/LinearSpace; + public static synthetic fun buffered$default (Lspace/kscience/kmath/linear/LinearSpace$Companion;Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lspace/kscience/kmath/linear/LinearSpace; + public final fun getReal ()Lspace/kscience/kmath/linear/LinearSpace; } public final class space/kscience/kmath/linear/LinearSpaceKt { - public static final fun asMatrix (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/linear/VirtualMatrix; - public static final fun asVector (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/structures/Buffer; public static final fun invoke (Lspace/kscience/kmath/linear/LinearSpace;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; } @@ -685,12 +565,11 @@ public abstract interface class space/kscience/kmath/linear/LupDecompositionFeat public final class space/kscience/kmath/linear/LupDecompositionKt { public static final fun abs (Lspace/kscience/kmath/linear/LinearSpace;Ljava/lang/Comparable;)Ljava/lang/Comparable; - public static final fun lup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;D)Lspace/kscience/kmath/linear/LupDecomposition; - public static final fun lup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/structures/MutableBufferFactory;Lspace/kscience/kmath/nd/Structure2D;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/linear/LupDecomposition; - public static synthetic fun lup$default (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;DILjava/lang/Object;)Lspace/kscience/kmath/linear/LupDecomposition; - public static final fun lupSolver (Lspace/kscience/kmath/linear/LinearSpace;D)Lspace/kscience/kmath/linear/LinearSolver; - public static final fun lupSolver (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/structures/MutableBufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/linear/LinearSolver; - public static synthetic fun lupSolver$default (Lspace/kscience/kmath/linear/LinearSpace;DILjava/lang/Object;)Lspace/kscience/kmath/linear/LinearSolver; + public static final fun inverseWithLup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; + public static final fun lup (Lspace/kscience/kmath/linear/LinearSpace;Lkotlin/jvm/functions/Function2;Lspace/kscience/kmath/nd/Structure2D;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/linear/LupDecomposition; + public static final fun lup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/linear/LupDecomposition; + public static final fun solveWithLup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; + public static final fun solveWithLup (Lspace/kscience/kmath/linear/LupDecomposition;Lkotlin/jvm/functions/Function2;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; } public final class space/kscience/kmath/linear/MatrixBuilder { @@ -706,7 +585,6 @@ public final class space/kscience/kmath/linear/MatrixBuilderKt { public static final fun column (Lspace/kscience/kmath/linear/LinearSpace;[Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D; public static final fun row (Lspace/kscience/kmath/linear/LinearSpace;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/Structure2D; public static final fun row (Lspace/kscience/kmath/linear/LinearSpace;[Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D; - public static final fun symmetric (Lspace/kscience/kmath/linear/MatrixBuilder;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/Structure2D; } public abstract interface class space/kscience/kmath/linear/MatrixFeature : space/kscience/kmath/nd/StructureFeature { @@ -723,23 +601,20 @@ public final class space/kscience/kmath/linear/MatrixWrapper : space/kscience/km public fun getColNum ()I public fun getColumns ()Ljava/util/List; public fun getDimension ()I - public synthetic fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object; - public fun getFeature (Lkotlin/reflect/KClass;)Lspace/kscience/kmath/nd/StructureFeature; - public final fun getFeatures-En6fw3w ()Ljava/util/Map; - public fun getIndices ()Lspace/kscience/kmath/nd/ShapeIndexer; + public final fun getFeatures ()Ljava/util/Set; public final fun getOrigin ()Lspace/kscience/kmath/nd/Structure2D; public fun getRowNum ()I public fun getRows ()Ljava/util/List; - public fun getShape-IIYLAfE ()[I + public fun getShape ()[I public fun toString ()Ljava/lang/String; } public final class space/kscience/kmath/linear/MatrixWrapperKt { + public static final fun getOrigin (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; public static final fun one (Lspace/kscience/kmath/linear/LinearSpace;II)Lspace/kscience/kmath/nd/Structure2D; + public static final fun plus (Lspace/kscience/kmath/nd/Structure2D;Ljava/util/Collection;)Lspace/kscience/kmath/linear/MatrixWrapper; public static final fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/linear/MatrixFeature;)Lspace/kscience/kmath/linear/MatrixWrapper; public static final fun transpose (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public static final fun withFeature (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/linear/MatrixFeature;)Lspace/kscience/kmath/linear/MatrixWrapper; - public static final fun withFeatures (Lspace/kscience/kmath/nd/Structure2D;Ljava/lang/Iterable;)Lspace/kscience/kmath/linear/MatrixWrapper; public static final fun zero (Lspace/kscience/kmath/linear/LinearSpace;II)Lspace/kscience/kmath/nd/Structure2D; } @@ -759,10 +634,6 @@ public abstract interface class space/kscience/kmath/linear/SingularValueDecompo public abstract fun getV ()Lspace/kscience/kmath/nd/Structure2D; } -public final class space/kscience/kmath/linear/SymmetricMatrixFeature : space/kscience/kmath/linear/MatrixFeature { - public static final field INSTANCE Lspace/kscience/kmath/linear/SymmetricMatrixFeature; -} - public final class space/kscience/kmath/linear/TransposedFeature : space/kscience/kmath/linear/MatrixFeature { public fun (Lspace/kscience/kmath/nd/Structure2D;)V public final fun getOriginal ()Lspace/kscience/kmath/nd/Structure2D; @@ -782,22 +653,13 @@ public final class space/kscience/kmath/linear/VirtualMatrix : space/kscience/km public fun getColNum ()I public final fun getGenerator ()Lkotlin/jvm/functions/Function2; public fun getRowNum ()I - public fun getShape-IIYLAfE ()[I -} - -public final class space/kscience/kmath/linear/VirtualMatrixKt { - public static final fun virtual (Lspace/kscience/kmath/linear/MatrixBuilder;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/linear/VirtualMatrix; + public fun getShape ()[I } public final class space/kscience/kmath/linear/ZeroFeature : space/kscience/kmath/linear/DiagonalFeature { public static final field INSTANCE Lspace/kscience/kmath/linear/ZeroFeature; } -public final class space/kscience/kmath/misc/CollectionsKt { - public static final fun zipWithNextCircular (Ljava/util/List;)Ljava/util/List; - public static final fun zipWithNextCircular (Ljava/util/List;Lkotlin/jvm/functions/Function2;)Ljava/util/List; -} - public final class space/kscience/kmath/misc/CumulativeKt { public static final fun cumulative (Ljava/lang/Iterable;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Iterable; public static final fun cumulative (Ljava/util/Iterator;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/Iterator; @@ -806,7 +668,6 @@ public final class space/kscience/kmath/misc/CumulativeKt { public static final fun cumulativeSum (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Iterable; public static final fun cumulativeSum (Ljava/util/List;Lspace/kscience/kmath/operations/Ring;)Ljava/util/List; public static final fun cumulativeSum (Lkotlin/sequences/Sequence;Lspace/kscience/kmath/operations/Ring;)Lkotlin/sequences/Sequence; - public static final fun cumulativeSum (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/operations/Ring;)Lspace/kscience/kmath/structures/Buffer; public static final fun cumulativeSumOfDouble (Ljava/lang/Iterable;)Ljava/lang/Iterable; public static final fun cumulativeSumOfDouble (Ljava/util/List;)Ljava/util/List; public static final fun cumulativeSumOfDouble (Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence; @@ -818,323 +679,192 @@ public final class space/kscience/kmath/misc/CumulativeKt { public static final fun cumulativeSumOfLong (Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence; } -public abstract interface class space/kscience/kmath/misc/Feature { - public fun getKey ()Lkotlin/reflect/KClass; -} - -public final class space/kscience/kmath/misc/FeatureSet : space/kscience/kmath/misc/Featured { - public static final field Companion Lspace/kscience/kmath/misc/FeatureSet$Companion; - public static final synthetic fun box-impl (Ljava/util/Map;)Lspace/kscience/kmath/misc/FeatureSet; +public final class space/kscience/kmath/misc/StringSymbol : space/kscience/kmath/misc/Symbol { + public static final synthetic fun box-impl (Ljava/lang/String;)Lspace/kscience/kmath/misc/StringSymbol; + public static fun constructor-impl (Ljava/lang/String;)Ljava/lang/String; public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl (Ljava/util/Map;Ljava/lang/Object;)Z - public static final fun equals-impl0 (Ljava/util/Map;Ljava/util/Map;)Z - public synthetic fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object; - public fun getFeature (Lkotlin/reflect/KClass;)Lspace/kscience/kmath/misc/Feature; - public static fun getFeature-impl (Ljava/util/Map;Lkotlin/reflect/KClass;)Lspace/kscience/kmath/misc/Feature; - public final fun getFeatures ()Ljava/util/Map; + public static fun equals-impl (Ljava/lang/String;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Ljava/lang/String;Ljava/lang/String;)Z + public fun getIdentity ()Ljava/lang/String; public fun hashCode ()I - public static fun hashCode-impl (Ljava/util/Map;)I - public static final fun iterator-impl (Ljava/util/Map;)Ljava/util/Iterator; + public static fun hashCode-impl (Ljava/lang/String;)I public fun toString ()Ljava/lang/String; - public static fun toString-impl (Ljava/util/Map;)Ljava/lang/String; - public final synthetic fun unbox-impl ()Ljava/util/Map; - public static final fun with-JVE9-Rk (Ljava/util/Map;Ljava/lang/Iterable;)Ljava/util/Map; - public static final fun with-JVE9-Rk (Ljava/util/Map;[Lspace/kscience/kmath/misc/Feature;)Ljava/util/Map; - public static final fun with-YU1a0hQ (Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map; - public static final fun with-h58Sd8I (Ljava/util/Map;Lspace/kscience/kmath/misc/Feature;Lkotlin/reflect/KClass;)Ljava/util/Map; - public static synthetic fun with-h58Sd8I$default (Ljava/util/Map;Lspace/kscience/kmath/misc/Feature;Lkotlin/reflect/KClass;ILjava/lang/Object;)Ljava/util/Map; + public static fun toString-impl (Ljava/lang/String;)Ljava/lang/String; + public final synthetic fun unbox-impl ()Ljava/lang/String; } -public final class space/kscience/kmath/misc/FeatureSet$Companion { - public final fun of-JVE9-Rk (Ljava/lang/Iterable;)Ljava/util/Map; - public final fun of-JVE9-Rk ([Lspace/kscience/kmath/misc/Feature;)Ljava/util/Map; +public abstract interface class space/kscience/kmath/misc/Symbol { + public static final field Companion Lspace/kscience/kmath/misc/Symbol$Companion; + public abstract fun getIdentity ()Ljava/lang/String; } -public abstract interface class space/kscience/kmath/misc/Featured { - public abstract fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object; +public final class space/kscience/kmath/misc/Symbol$Companion { + public final fun getX-tWtZOCg ()Ljava/lang/String; + public final fun getY-tWtZOCg ()Ljava/lang/String; + public final fun getZ-tWtZOCg ()Ljava/lang/String; } -public abstract interface class space/kscience/kmath/misc/Loggable { - public static final field Companion Lspace/kscience/kmath/misc/Loggable$Companion; - public static final field INFO Ljava/lang/String; - public abstract fun log (Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V +public final class space/kscience/kmath/misc/SymbolKt { + public static final fun getSymbol ()Lkotlin/properties/ReadOnlyProperty; } -public final class space/kscience/kmath/misc/Loggable$Companion { - public static final field INFO Ljava/lang/String; - public final fun getConsole ()Lspace/kscience/kmath/misc/Loggable; +public abstract interface annotation class space/kscience/kmath/misc/UnstableKMathAPI : java/lang/annotation/Annotation { } -public final class space/kscience/kmath/misc/LoggingKt { - public static final fun log (Lspace/kscience/kmath/misc/Loggable;Lkotlin/jvm/functions/Function0;)V -} - -public final class space/kscience/kmath/misc/NumbersJVMKt { - public static final fun toIntExact (J)I -} - -public final class space/kscience/kmath/misc/SortingKt { - public static final fun requireSorted (Lspace/kscience/kmath/structures/Buffer;)V - public static final fun sorted (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun sortedBy (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public static final fun sortedByDescending (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public static final fun sortedDescending (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; -} - -public abstract interface class space/kscience/kmath/nd/AlgebraND : space/kscience/kmath/operations/Algebra { +public abstract interface class space/kscience/kmath/nd/AlgebraND { public static final field Companion Lspace/kscience/kmath/nd/AlgebraND$Companion; - public abstract fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra; + public abstract fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; + public abstract fun getElementContext ()Lspace/kscience/kmath/operations/Algebra; + public abstract fun getShape ()[I public fun invoke (Lkotlin/jvm/functions/Function1;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public abstract fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; + public abstract fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; + public abstract fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; + public abstract fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; } public final class space/kscience/kmath/nd/AlgebraND$Companion { } -public final class space/kscience/kmath/nd/AlgebraNDExtentionsKt { - public static final fun one-waz_sdI (Lspace/kscience/kmath/nd/AlgebraND;[I)Lspace/kscience/kmath/nd/StructureND; - public static final fun oneVarArg (Lspace/kscience/kmath/nd/AlgebraND;I[I)Lspace/kscience/kmath/nd/StructureND; - public static final fun structureND (Lspace/kscience/kmath/nd/AlgebraND;I[ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public static final fun zero-waz_sdI (Lspace/kscience/kmath/nd/AlgebraND;[I)Lspace/kscience/kmath/nd/StructureND; - public static final fun zeroVarArg (Lspace/kscience/kmath/nd/AlgebraND;I[I)Lspace/kscience/kmath/nd/StructureND; -} - public abstract interface class space/kscience/kmath/nd/BufferAlgebraND : space/kscience/kmath/nd/AlgebraND { - public static final field Companion Lspace/kscience/kmath/nd/BufferAlgebraND$Companion; - public abstract fun getBufferAlgebra ()Lspace/kscience/kmath/operations/BufferAlgebra; - public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra; - public abstract fun getIndexerBuilder ()Lkotlin/jvm/functions/Function1; + public fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; + public fun getBuffer (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/structures/Buffer; + public abstract fun getBufferFactory ()Lkotlin/jvm/functions/Function2; + public abstract fun getStrides ()Lspace/kscience/kmath/nd/Strides; public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; public synthetic fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public fun toBufferND (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; -} - -public final class space/kscience/kmath/nd/BufferAlgebraND$Companion { - public final fun getDefaultIndexerBuilder ()Lkotlin/jvm/functions/Function1; + public fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; } public final class space/kscience/kmath/nd/BufferAlgebraNDKt { - public static final fun getNd (Lspace/kscience/kmath/operations/BufferAlgebra;)Lspace/kscience/kmath/nd/BufferedFieldOpsND; - public static final fun getNd (Lspace/kscience/kmath/operations/BufferAlgebra;)Lspace/kscience/kmath/nd/BufferedGroupNDOps; - public static final fun getNd (Lspace/kscience/kmath/operations/BufferAlgebra;)Lspace/kscience/kmath/nd/BufferedRingOpsND; - public static final fun mapInline (Lspace/kscience/kmath/nd/BufferAlgebraND;Lspace/kscience/kmath/nd/BufferND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public static final fun structureND (Lspace/kscience/kmath/nd/BufferAlgebraND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public static final fun structureND (Lspace/kscience/kmath/nd/BufferAlgebraND;[ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; + public static final fun field (Lspace/kscience/kmath/nd/AlgebraND$Companion;Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedFieldND; + public static final fun group (Lspace/kscience/kmath/nd/AlgebraND$Companion;Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedGroupND; + public static final fun ndField (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun ndGroup (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun ndRing (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun ring (Lspace/kscience/kmath/nd/AlgebraND$Companion;Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedRingND; } -public class space/kscience/kmath/nd/BufferND : space/kscience/kmath/nd/StructureND { - public fun (Lspace/kscience/kmath/nd/ShapeIndexer;Lspace/kscience/kmath/structures/Buffer;)V +public final class space/kscience/kmath/nd/BufferND : space/kscience/kmath/nd/StructureND { + public fun (Lspace/kscience/kmath/nd/Strides;Lspace/kscience/kmath/structures/Buffer;)V + public fun elements ()Lkotlin/sequences/Sequence; public fun get ([I)Ljava/lang/Object; - public fun getBuffer ()Lspace/kscience/kmath/structures/Buffer; - public fun getIndices ()Lspace/kscience/kmath/nd/ShapeIndexer; - public fun getShape-IIYLAfE ()[I + public final fun getBuffer ()Lspace/kscience/kmath/structures/Buffer; + public fun getShape ()[I + public final fun getStrides ()Lspace/kscience/kmath/nd/Strides; public fun toString ()Ljava/lang/String; } -public final class space/kscience/kmath/nd/BufferNDKt { - public static final fun BufferND-bYNkpeI ([ILspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; - public static synthetic fun BufferND-bYNkpeI$default ([ILspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND; - public static final fun MutableBufferND-bYNkpeI ([ILspace/kscience/kmath/structures/MutableBufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/MutableBufferND; - public static synthetic fun MutableBufferND-bYNkpeI$default ([ILspace/kscience/kmath/structures/MutableBufferFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/MutableBufferND; -} - -public class space/kscience/kmath/nd/BufferedFieldOpsND : space/kscience/kmath/nd/BufferedRingOpsND, space/kscience/kmath/nd/FieldOpsND { - public fun (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;)V - public synthetic fun (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function1;)V - public synthetic fun (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +public class space/kscience/kmath/nd/BufferedFieldND : space/kscience/kmath/nd/BufferedRingND, space/kscience/kmath/nd/FieldND { + public fun ([ILspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function2;)V public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND; } -public class space/kscience/kmath/nd/BufferedGroupNDOps : space/kscience/kmath/nd/BufferAlgebraND, space/kscience/kmath/nd/GroupOpsND { - public fun (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;)V - public synthetic fun (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun getBufferAlgebra ()Lspace/kscience/kmath/operations/BufferAlgebra; - public fun getIndexerBuilder ()Lkotlin/jvm/functions/Function1; +public class space/kscience/kmath/nd/BufferedGroupND : space/kscience/kmath/nd/BufferAlgebraND, space/kscience/kmath/nd/GroupND { + public fun ([ILspace/kscience/kmath/operations/Group;Lkotlin/jvm/functions/Function2;)V + public final fun getBufferFactory ()Lkotlin/jvm/functions/Function2; + public synthetic fun getElementContext ()Lspace/kscience/kmath/operations/Algebra; + public final fun getElementContext ()Lspace/kscience/kmath/operations/Group; + public final fun getShape ()[I + public fun getStrides ()Lspace/kscience/kmath/nd/Strides; + public synthetic fun getZero ()Ljava/lang/Object; + public fun getZero ()Lspace/kscience/kmath/nd/BufferND; public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; } -public class space/kscience/kmath/nd/BufferedRingOpsND : space/kscience/kmath/nd/BufferedGroupNDOps, space/kscience/kmath/nd/RingOpsND { - public fun (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;)V - public synthetic fun (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +public class space/kscience/kmath/nd/BufferedRingND : space/kscience/kmath/nd/BufferedGroupND, space/kscience/kmath/nd/RingND { + public fun ([ILspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;)V + public synthetic fun getOne ()Ljava/lang/Object; + public fun getOne ()Lspace/kscience/kmath/nd/BufferND; } -public final class space/kscience/kmath/nd/ColumnStrides : space/kscience/kmath/nd/Strides { - public static final field Companion Lspace/kscience/kmath/nd/ColumnStrides$Companion; +public final class space/kscience/kmath/nd/DefaultStrides : space/kscience/kmath/nd/Strides { + public static final field Companion Lspace/kscience/kmath/nd/DefaultStrides$Companion; public synthetic fun ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun equals (Ljava/lang/Object;)Z public fun getLinearSize ()I - public fun getShape-IIYLAfE ()[I + public fun getShape ()[I + public fun getStrides ()Ljava/util/List; public fun hashCode ()I public fun index (I)[I + public fun offset ([I)I } -public final class space/kscience/kmath/nd/ColumnStrides$Companion { +public final class space/kscience/kmath/nd/DefaultStrides$Companion { + public final fun invoke ([I)Lspace/kscience/kmath/nd/Strides; } -public final class space/kscience/kmath/nd/DoubleBufferND : space/kscience/kmath/nd/MutableBufferND, space/kscience/kmath/nd/MutableStructureNDOfDouble { - public synthetic fun (Lspace/kscience/kmath/nd/ShapeIndexer;[DLkotlin/jvm/internal/DefaultConstructorMarker;)V - public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/Buffer; - public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun getBuffer-Dv3HvWU ()[D - public fun getDouble ([I)D - public fun setDouble ([ID)V -} - -public final class space/kscience/kmath/nd/DoubleFieldND : space/kscience/kmath/nd/DoubleFieldOpsND, space/kscience/kmath/nd/FieldND, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumbersAddOps { - public synthetic fun ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V +public final class space/kscience/kmath/nd/DoubleFieldND : space/kscience/kmath/nd/BufferedFieldND, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/ScaleOperations { + public fun ([I)V + public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; + public fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; + public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; + public fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; + public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; + public fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; + public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; + public fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; + public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; + public fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public fun getShape-IIYLAfE ()[I + public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; + public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun getBuffer (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/structures/Buffer; + public fun getBuffer-Udx-57Q (Lspace/kscience/kmath/nd/StructureND;)[D + public synthetic fun getOne ()Ljava/lang/Object; + public fun getOne ()Lspace/kscience/kmath/nd/BufferND; + public synthetic fun getZero ()Ljava/lang/Object; + public fun getZero ()Lspace/kscience/kmath/nd/BufferND; + public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; + public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; + public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; + public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun power (Ljava/lang/Object;I)Ljava/lang/Object; + public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/BufferND; public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Lspace/kscience/kmath/nd/StructureND;I)Lspace/kscience/kmath/nd/DoubleBufferND; - public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun power-Qn1smSk (Ljava/lang/Object;I)Ljava/lang/Object; - public fun power-Qn1smSk (Lspace/kscience/kmath/nd/StructureND;I)Lspace/kscience/kmath/nd/DoubleBufferND; + public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/BufferND; + public fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; + public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; + public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND; + public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; + public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; + public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; + public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; + public fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; + public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; } public final class space/kscience/kmath/nd/DoubleFieldNDKt { - public static final fun getNdAlgebra (Lspace/kscience/kmath/operations/DoubleField;)Lspace/kscience/kmath/nd/DoubleFieldOpsND; - public static final fun ndAlgebra (Lspace/kscience/kmath/operations/DoubleField;[I)Lspace/kscience/kmath/nd/DoubleFieldND; - public static final fun ndAlgebra-waz_sdI (Lspace/kscience/kmath/operations/DoubleField;[I)Lspace/kscience/kmath/nd/DoubleFieldND; + public static final fun nd (Lspace/kscience/kmath/operations/DoubleField;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun real (Lspace/kscience/kmath/nd/AlgebraND$Companion;[I)Lspace/kscience/kmath/nd/DoubleFieldND; } -public abstract class space/kscience/kmath/nd/DoubleFieldOpsND : space/kscience/kmath/nd/BufferedFieldOpsND, space/kscience/kmath/operations/ExtendedFieldOps, space/kscience/kmath/operations/ScaleOperations { - public static final field Companion Lspace/kscience/kmath/nd/DoubleFieldOpsND$Companion; - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public fun div (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun div (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public synthetic fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun div (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/DoubleBufferND; - public fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; - public fun div (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - protected final fun mapInline (Lspace/kscience/kmath/nd/DoubleBufferND;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/DoubleBufferND; - public fun minus (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun minus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; - public fun minus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun plus (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public synthetic fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun plus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; - public fun plus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun times (Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object; - public fun times (Ljava/lang/Number;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun times (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/DoubleBufferND; - public fun times (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun toBufferND (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public fun toBufferND (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public synthetic fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryPlus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND; - public fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; -} - -public final class space/kscience/kmath/nd/DoubleFieldOpsND$Companion : space/kscience/kmath/nd/DoubleFieldOpsND { -} - -public abstract interface class space/kscience/kmath/nd/FieldND : space/kscience/kmath/nd/FieldOpsND, space/kscience/kmath/nd/RingND, space/kscience/kmath/nd/WithShape, space/kscience/kmath/operations/Field { - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/nd/StructureND; -} - -public abstract interface class space/kscience/kmath/nd/FieldOpsND : space/kscience/kmath/nd/RingOpsND, space/kscience/kmath/operations/FieldOps, space/kscience/kmath/operations/ScaleOperations { +public abstract interface class space/kscience/kmath/nd/FieldND : space/kscience/kmath/nd/RingND, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/ScaleOperations { public fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; public fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND; } -public abstract interface class space/kscience/kmath/nd/GroupND : space/kscience/kmath/nd/GroupOpsND, space/kscience/kmath/nd/WithShape, space/kscience/kmath/operations/Group { - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/nd/StructureND; -} - -public abstract interface class space/kscience/kmath/nd/GroupOpsND : space/kscience/kmath/nd/AlgebraND, space/kscience/kmath/operations/GroupOps { - public static final field Companion Lspace/kscience/kmath/nd/GroupOpsND$Companion; +public abstract interface class space/kscience/kmath/nd/GroupND : space/kscience/kmath/nd/AlgebraND, space/kscience/kmath/operations/Group { + public static final field Companion Lspace/kscience/kmath/nd/GroupND$Companion; public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; public fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; @@ -1143,217 +873,52 @@ public abstract interface class space/kscience/kmath/nd/GroupOpsND : space/kscie public fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; } -public final class space/kscience/kmath/nd/GroupOpsND$Companion { -} - -public final class space/kscience/kmath/nd/IndexOutOfShapeException : java/lang/RuntimeException { - public synthetic fun ([I[ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getIndex ()[I - public final fun getShape-IIYLAfE ()[I -} - -public final class space/kscience/kmath/nd/IntBufferND : space/kscience/kmath/nd/MutableBufferND { - public synthetic fun (Lspace/kscience/kmath/nd/ShapeIndexer;[ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/Buffer; - public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun getBuffer-ir4F4A8 ()[I -} - -public final class space/kscience/kmath/nd/IntRingND : space/kscience/kmath/nd/IntRingOpsND, space/kscience/kmath/nd/RingND, space/kscience/kmath/operations/NumbersAddOps { - public synthetic fun ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun getShape-IIYLAfE ()[I - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/BufferND; -} - -public final class space/kscience/kmath/nd/IntRingNDKt { - public static final fun withNdAlgebra (Lspace/kscience/kmath/operations/IntRing;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; -} - -public abstract class space/kscience/kmath/nd/IntRingOpsND : space/kscience/kmath/nd/BufferedRingOpsND { - public static final field Companion Lspace/kscience/kmath/nd/IntRingOpsND$Companion; - public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/IntBufferND; - public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; -} - -public final class space/kscience/kmath/nd/IntRingOpsND$Companion : space/kscience/kmath/nd/IntRingOpsND { -} - -public class space/kscience/kmath/nd/MutableBufferND : space/kscience/kmath/nd/BufferND, space/kscience/kmath/nd/MutableStructureND { - public fun (Lspace/kscience/kmath/nd/ShapeIndexer;Lspace/kscience/kmath/structures/MutableBuffer;)V - public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/Buffer; - public fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun set ([ILjava/lang/Object;)V -} - -public abstract interface class space/kscience/kmath/nd/MutableStructure1D : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/Structure1D, space/kscience/kmath/structures/MutableBuffer { - public fun set ([ILjava/lang/Object;)V -} - -public abstract interface class space/kscience/kmath/nd/MutableStructure2D : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/Structure2D { - public fun getColumns ()Ljava/util/List; - public fun getRows ()Ljava/util/List; - public abstract fun set (IILjava/lang/Object;)V +public final class space/kscience/kmath/nd/GroupND$Companion { } public abstract interface class space/kscience/kmath/nd/MutableStructureND : space/kscience/kmath/nd/StructureND { public abstract fun set ([ILjava/lang/Object;)V } -public abstract interface class space/kscience/kmath/nd/MutableStructureNDOfDouble : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/StructureNDOfDouble { - public abstract fun setDouble ([ID)V -} - -public final class space/kscience/kmath/nd/OperationsNDKt { - public static final fun roll (Lspace/kscience/kmath/nd/StructureND;II)Lspace/kscience/kmath/nd/StructureND; - public static final fun roll (Lspace/kscience/kmath/nd/StructureND;Lkotlin/Pair;[Lkotlin/Pair;)Lspace/kscience/kmath/nd/StructureND; - public static synthetic fun roll$default (Lspace/kscience/kmath/nd/StructureND;IIILjava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; -} - -public final class space/kscience/kmath/nd/PermutedMutableStructureND : space/kscience/kmath/nd/MutableStructureND { - public synthetic fun (Lspace/kscience/kmath/nd/MutableStructureND;[ILkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public synthetic fun (Lspace/kscience/kmath/nd/MutableStructureND;[ILkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun get ([I)Ljava/lang/Object; - public final fun getOrigin ()Lspace/kscience/kmath/nd/MutableStructureND; - public final fun getPermutation ()Lkotlin/jvm/functions/Function1; - public fun getShape-IIYLAfE ()[I - public fun set ([ILjava/lang/Object;)V -} - -public final class space/kscience/kmath/nd/PermutedStructureND : space/kscience/kmath/nd/StructureND { - public fun (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function1;)V - public fun get ([I)Ljava/lang/Object; - public final fun getOrigin ()Lspace/kscience/kmath/nd/StructureND; - public final fun getPermutation ()Lkotlin/jvm/functions/Function1; - public fun getShape-IIYLAfE ()[I -} - -public final class space/kscience/kmath/nd/PermutedStructureNDKt { - public static final fun permute (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/PermutedStructureND; - public static final fun permute-_A0By-k (Lspace/kscience/kmath/nd/MutableStructureND;[ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/PermutedMutableStructureND; - public static synthetic fun permute-_A0By-k$default (Lspace/kscience/kmath/nd/MutableStructureND;[ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/PermutedMutableStructureND; -} - -public final class space/kscience/kmath/nd/PrimitiveStructureNDKt { - public static final fun getDouble (Lspace/kscience/kmath/nd/MutableStructureND;[I)D - public static final fun getDouble (Lspace/kscience/kmath/nd/StructureND;[I)D - public static final fun getInt (Lspace/kscience/kmath/nd/StructureND;[I)I -} - -public abstract interface class space/kscience/kmath/nd/RingND : space/kscience/kmath/nd/GroupND, space/kscience/kmath/nd/RingOpsND, space/kscience/kmath/nd/WithShape, space/kscience/kmath/operations/Ring { - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/nd/StructureND; -} - -public abstract interface class space/kscience/kmath/nd/RingOpsND : space/kscience/kmath/nd/GroupOpsND, space/kscience/kmath/operations/RingOps { - public static final field Companion Lspace/kscience/kmath/nd/RingOpsND$Companion; +public abstract interface class space/kscience/kmath/nd/RingND : space/kscience/kmath/nd/GroupND, space/kscience/kmath/operations/Ring { + public static final field Companion Lspace/kscience/kmath/nd/RingND$Companion; public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; public fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; public fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; } -public final class space/kscience/kmath/nd/RingOpsND$Companion { -} - -public final class space/kscience/kmath/nd/RowStrides : space/kscience/kmath/nd/Strides { - public static final field Companion Lspace/kscience/kmath/nd/RowStrides$Companion; - public synthetic fun ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun equals (Ljava/lang/Object;)Z - public fun getLinearSize ()I - public fun getShape-IIYLAfE ()[I - public fun hashCode ()I - public fun index (I)[I -} - -public final class space/kscience/kmath/nd/RowStrides$Companion { -} - -public abstract interface class space/kscience/kmath/nd/ShapeIndexer : java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker { - public abstract fun asSequence ()Lkotlin/sequences/Sequence; - public abstract fun equals (Ljava/lang/Object;)Z - public abstract fun getLinearSize ()I - public abstract fun getShape-IIYLAfE ()[I - public abstract fun hashCode ()I - public abstract fun index (I)[I - public fun iterator ()Ljava/util/Iterator; - public abstract fun offset ([I)I -} - -public final class space/kscience/kmath/nd/ShapeIndicesKt { - public static final fun Strides-dNlrn20 ([I)Lspace/kscience/kmath/nd/Strides; +public final class space/kscience/kmath/nd/RingND$Companion { } public final class space/kscience/kmath/nd/ShapeMismatchException : java/lang/RuntimeException { - public synthetic fun ([I[ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getActual-IIYLAfE ()[I - public final fun getExpected-IIYLAfE ()[I + public fun ([I[I)V + public final fun getActual ()[I + public final fun getExpected ()[I } -public final class space/kscience/kmath/nd/ShapeND { - public static final synthetic fun box-impl ([I)Lspace/kscience/kmath/nd/ShapeND; - public static fun constructor-impl ([I)[I - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl ([ILjava/lang/Object;)Z - public static final fun equals-impl0 ([I[I)Z - public static final fun get-impl ([II)I - public static final fun getSize-impl ([I)I - public fun hashCode ()I - public static fun hashCode-impl ([I)I - public fun toString ()Ljava/lang/String; - public static fun toString-impl ([I)Ljava/lang/String; - public final synthetic fun unbox-impl ()[I -} - -public final class space/kscience/kmath/nd/ShapeNDKt { - public static final fun ShapeND (I[I)[I - public static final fun asArray-dNlrn20 ([I)[I - public static final fun asList-dNlrn20 ([I)Ljava/util/List; - public static final fun component1-dNlrn20 ([I)I - public static final fun component2-dNlrn20 ([I)I - public static final fun component3-dNlrn20 ([I)I - public static final fun contentEquals-9Nqdy04 ([I[I)Z - public static final fun contentHashCode-dNlrn20 ([I)I - public static final fun first-dNlrn20 ([I)I - public static final fun first-qL90JFI ([II)[I - public static final fun forEach-qL90JFI ([ILkotlin/jvm/functions/Function1;)V - public static final fun forEachIndexed-qL90JFI ([ILkotlin/jvm/functions/Function2;)V - public static final fun getIndices-dNlrn20 ([I)Lkotlin/ranges/IntRange; - public static final fun getLinearSize-dNlrn20 ([I)I - public static final fun isEmpty-dNlrn20 ([I)Z - public static final fun isNotEmpty-dNlrn20 ([I)Z - public static final fun last-dNlrn20 ([I)I - public static final fun last-qL90JFI ([II)[I - public static final fun plus-9Nqdy04 ([I[I)[I - public static final fun plus-qL90JFI ([I[I)[I - public static final fun slice-qL90JFI ([ILkotlin/ranges/IntRange;)[I - public static final fun toArray-dNlrn20 ([I)[I - public static final fun transposed-bYNkpeI ([III)[I -} - -public final class space/kscience/kmath/nd/ShortRingND : space/kscience/kmath/nd/ShortRingOpsND, space/kscience/kmath/nd/RingND, space/kscience/kmath/operations/NumbersAddOps { - public synthetic fun ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun getShape-IIYLAfE ()[I +public final class space/kscience/kmath/nd/ShortRingND : space/kscience/kmath/nd/BufferedRingND, space/kscience/kmath/operations/NumbersAddOperations { + public fun ([I)V + public synthetic fun getOne ()Ljava/lang/Object; + public fun getOne ()Lspace/kscience/kmath/nd/BufferND; + public synthetic fun getZero ()Ljava/lang/Object; + public fun getZero ()Lspace/kscience/kmath/nd/BufferND; public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/BufferND; } public final class space/kscience/kmath/nd/ShortRingNDKt { - public static final fun withNdAlgebra (Lspace/kscience/kmath/operations/ShortRing;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun nd (Lspace/kscience/kmath/operations/ShortRing;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun produceInline (Lspace/kscience/kmath/nd/BufferedRingND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; } -public abstract class space/kscience/kmath/nd/ShortRingOpsND : space/kscience/kmath/nd/BufferedRingOpsND { - public static final field Companion Lspace/kscience/kmath/nd/ShortRingOpsND$Companion; -} - -public final class space/kscience/kmath/nd/ShortRingOpsND$Companion : space/kscience/kmath/nd/ShortRingOpsND { -} - -public abstract class space/kscience/kmath/nd/Strides : space/kscience/kmath/nd/ShapeIndexer { - public fun ()V - public fun asSequence ()Lkotlin/sequences/Sequence; - public fun offset ([I)I +public abstract interface class space/kscience/kmath/nd/Strides { + public abstract fun getLinearSize ()I + public abstract fun getShape ()[I + public abstract fun getStrides ()Ljava/util/List; + public abstract fun index (I)[I + public fun indices ()Lkotlin/sequences/Sequence; + public abstract fun offset ([I)I } public abstract interface class space/kscience/kmath/nd/Structure1D : space/kscience/kmath/nd/StructureND, space/kscience/kmath/structures/Buffer { @@ -1367,7 +932,6 @@ public final class space/kscience/kmath/nd/Structure1D$Companion { } public final class space/kscience/kmath/nd/Structure1DKt { - public static final fun as1D (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructure1D; public static final fun as1D (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Structure1D; public static final fun asND (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/nd/Structure1D; } @@ -1381,72 +945,41 @@ public abstract interface class space/kscience/kmath/nd/Structure2D : space/ksci public fun getColumns ()Ljava/util/List; public abstract fun getRowNum ()I public fun getRows ()Ljava/util/List; - public fun getShape-IIYLAfE ()[I + public fun getShape ()[I } public final class space/kscience/kmath/nd/Structure2D$Companion { } public final class space/kscience/kmath/nd/Structure2DKt { - public static final fun as2D (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructure2D; public static final fun as2D (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Structure2D; } -public abstract interface class space/kscience/kmath/nd/StructureFeature : space/kscience/kmath/misc/Feature { +public abstract interface class space/kscience/kmath/nd/StructureFeature { } -public abstract interface class space/kscience/kmath/nd/StructureND : space/kscience/kmath/misc/Featured, space/kscience/kmath/nd/WithShape { +public abstract interface class space/kscience/kmath/nd/StructureND { public static final field Companion Lspace/kscience/kmath/nd/StructureND$Companion; - public fun elements ()Lkotlin/sequences/Sequence; + public abstract fun elements ()Lkotlin/sequences/Sequence; public abstract fun get ([I)Ljava/lang/Object; public fun getDimension ()I - public synthetic fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object; - public fun getFeature (Lkotlin/reflect/KClass;)Lspace/kscience/kmath/nd/StructureFeature; - public abstract fun getShape-IIYLAfE ()[I + public abstract fun getShape ()[I } public final class space/kscience/kmath/nd/StructureND$Companion { public final fun auto (Lkotlin/reflect/KClass;Lspace/kscience/kmath/nd/Strides;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; public final fun auto (Lkotlin/reflect/KClass;[ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; - public final fun buffered (Lspace/kscience/kmath/nd/Strides;Lspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; - public static synthetic fun buffered$default (Lspace/kscience/kmath/nd/StructureND$Companion;Lspace/kscience/kmath/nd/Strides;Lspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND; - public final fun buffered-bYNkpeI ([ILspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; - public static synthetic fun buffered-bYNkpeI$default (Lspace/kscience/kmath/nd/StructureND$Companion;[ILspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND; + public final fun buffered (Lspace/kscience/kmath/nd/Strides;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; + public final fun buffered ([ILkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; + public static synthetic fun buffered$default (Lspace/kscience/kmath/nd/StructureND$Companion;Lspace/kscience/kmath/nd/Strides;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND; + public static synthetic fun buffered$default (Lspace/kscience/kmath/nd/StructureND$Companion;[ILkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND; public final fun contentEquals (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Z - public final fun contentEquals (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;D)Z - public static synthetic fun contentEquals$default (Lspace/kscience/kmath/nd/StructureND$Companion;Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;DILjava/lang/Object;)Z public final fun toString (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/String; } public final class space/kscience/kmath/nd/StructureNDKt { - public static final fun contentEquals (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Z - public static final fun contentEquals (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Comparable;)Z - public static final fun contentEquals (Lspace/kscience/kmath/nd/AlgebraND;Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Z - public static final fun contentEquals (Lspace/kscience/kmath/nd/GroupOpsND;Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Comparable;)Z - public static final fun get (Lspace/kscience/kmath/nd/StructureND;[I)D - public static final fun get (Lspace/kscience/kmath/nd/StructureND;[I)I public static final fun get (Lspace/kscience/kmath/nd/StructureND;[I)Ljava/lang/Object; - public static final fun set (Lspace/kscience/kmath/nd/MutableStructureND;[ILjava/lang/Object;)V -} - -public abstract interface class space/kscience/kmath/nd/StructureNDOfDouble : space/kscience/kmath/nd/StructureND { - public abstract fun getDouble ([I)D -} - -public abstract interface class space/kscience/kmath/nd/StructureNDOfInt : space/kscience/kmath/nd/StructureND { - public abstract fun getInt ([I)I -} - -public class space/kscience/kmath/nd/VirtualStructureND : space/kscience/kmath/nd/StructureND { - public synthetic fun ([ILkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun get ([I)Ljava/lang/Object; - public final fun getProducer ()Lkotlin/jvm/functions/Function1; - public fun getShape-IIYLAfE ()[I -} - -public abstract interface class space/kscience/kmath/nd/WithShape { - public fun getIndices ()Lspace/kscience/kmath/nd/ShapeIndexer; - public abstract fun getShape-IIYLAfE ()[I + public static final fun mapInPlace (Lspace/kscience/kmath/nd/MutableStructureND;Lkotlin/jvm/functions/Function2;)V } public abstract interface class space/kscience/kmath/operations/Algebra { @@ -1454,29 +987,37 @@ public abstract interface class space/kscience/kmath/operations/Algebra { public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; public fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; public fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory; public fun unaryOperation (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object; public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; } +public abstract interface class space/kscience/kmath/operations/AlgebraElement { + public abstract fun getContext ()Lspace/kscience/kmath/operations/Algebra; +} + +public final class space/kscience/kmath/operations/AlgebraElementsKt { + public static final fun div (Lspace/kscience/kmath/operations/AlgebraElement;Lspace/kscience/kmath/operations/AlgebraElement;)Lspace/kscience/kmath/operations/AlgebraElement; + public static final fun plus (Lspace/kscience/kmath/operations/AlgebraElement;Lspace/kscience/kmath/operations/AlgebraElement;)Lspace/kscience/kmath/operations/AlgebraElement; + public static final fun times (Lspace/kscience/kmath/operations/AlgebraElement;Lspace/kscience/kmath/operations/AlgebraElement;)Lspace/kscience/kmath/operations/AlgebraElement; +} + public final class space/kscience/kmath/operations/AlgebraExtensionsKt { - public static final fun abs (Lspace/kscience/kmath/operations/Group;Ljava/lang/Comparable;)Ljava/lang/Comparable; - public static final fun average (Lspace/kscience/kmath/operations/Group;Ljava/lang/Iterable;)Ljava/lang/Object; - public static final fun average (Lspace/kscience/kmath/operations/Group;Lkotlin/sequences/Sequence;)Ljava/lang/Object; - public static final fun average (Lspace/kscience/kmath/operations/Group;Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Object; - public static final fun averageWith (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Group;)Ljava/lang/Object; - public static final fun averageWith (Lkotlin/sequences/Sequence;Lspace/kscience/kmath/operations/Group;)Ljava/lang/Object; - public static final fun sum (Lspace/kscience/kmath/operations/Group;Ljava/lang/Iterable;)Ljava/lang/Object; - public static final fun sum (Lspace/kscience/kmath/operations/Group;Lkotlin/sequences/Sequence;)Ljava/lang/Object; - public static final fun sum (Lspace/kscience/kmath/operations/Group;Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Object; - public static final fun sumWith (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Group;)Ljava/lang/Object; - public static final fun sumWith (Lkotlin/sequences/Sequence;Lspace/kscience/kmath/operations/Group;)Ljava/lang/Object; - public static final fun sumWithGroupOf (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Group;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun abs (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Comparable;)Ljava/lang/Comparable; + public static final fun average (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Iterable;)Ljava/lang/Object; + public static final fun average (Lspace/kscience/kmath/operations/Ring;Lkotlin/sequences/Sequence;)Ljava/lang/Object; + public static final fun averageWith (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; + public static final fun averageWith (Lkotlin/sequences/Sequence;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; + public static final fun power (Lspace/kscience/kmath/operations/Field;Ljava/lang/Object;I)Ljava/lang/Object; + public static final fun power (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Object;I)Ljava/lang/Object; + public static final fun sum (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Iterable;)Ljava/lang/Object; + public static final fun sum (Lspace/kscience/kmath/operations/Ring;Lkotlin/sequences/Sequence;)Ljava/lang/Object; + public static final fun sumWith (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; + public static final fun sumWith (Lkotlin/sequences/Sequence;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; } public final class space/kscience/kmath/operations/AlgebraKt { - public static final fun bindSymbol (Lspace/kscience/kmath/operations/Algebra;Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object; - public static final fun bindSymbolOrNull (Lspace/kscience/kmath/operations/Algebra;Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object; + public static final fun bindSymbol (Lspace/kscience/kmath/operations/Algebra;Lspace/kscience/kmath/misc/Symbol;)Ljava/lang/Object; + public static final fun bindSymbolOrNull (Lspace/kscience/kmath/operations/Algebra;Lspace/kscience/kmath/misc/Symbol;)Ljava/lang/Object; public static final fun invoke (Lspace/kscience/kmath/operations/Algebra;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; } @@ -1497,7 +1038,6 @@ public final class space/kscience/kmath/operations/BigInt : java/lang/Comparable public final fun modPow (Lspace/kscience/kmath/operations/BigInt;Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; public final fun or (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; public final fun plus (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public final fun pow-WZ4Q5Ns (I)Lspace/kscience/kmath/operations/BigInt; public final fun rem (I)I public final fun rem (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; public final fun shl (I)Lspace/kscience/kmath/operations/BigInt; @@ -1514,7 +1054,7 @@ public final class space/kscience/kmath/operations/BigInt$Companion { public final fun getZERO ()Lspace/kscience/kmath/operations/BigInt; } -public final class space/kscience/kmath/operations/BigIntField : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumbersAddOps, space/kscience/kmath/operations/ScaleOperations { +public final class space/kscience/kmath/operations/BigIntField : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/ScaleOperations { public static final field INSTANCE Lspace/kscience/kmath/operations/BigIntField; public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun add (Lspace/kscience/kmath/operations/BigInt;Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; @@ -1538,10 +1078,9 @@ public final class space/kscience/kmath/operations/BigIntField : space/kscience/ public final class space/kscience/kmath/operations/BigIntKt { public static final fun abs (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public static final fun buffer (Lspace/kscience/kmath/operations/BigInt$Companion;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public static final fun getAlgebra (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigIntField; - public static final fun getNd (Lspace/kscience/kmath/operations/BigIntField;)Lspace/kscience/kmath/nd/BufferedRingOpsND; - public static final fun mutableBuffer (Lspace/kscience/kmath/operations/BigInt$Companion;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; + public static final fun bigInt (Lspace/kscience/kmath/nd/AlgebraND$Companion;[I)Lspace/kscience/kmath/nd/BufferedRingND; + public static final fun bigInt (Lspace/kscience/kmath/structures/Buffer$Companion;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; + public static final fun bigInt (Lspace/kscience/kmath/structures/MutableBuffer$Companion;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer; public static final fun parseBigInteger (Ljava/lang/String;)Lspace/kscience/kmath/operations/BigInt; public static final fun toBigInt (I)Lspace/kscience/kmath/operations/BigInt; public static final fun toBigInt (J)Lspace/kscience/kmath/operations/BigInt; @@ -1550,96 +1089,10 @@ public final class space/kscience/kmath/operations/BigIntKt { public static final fun toBigInt-WZ4Q5Ns (I)Lspace/kscience/kmath/operations/BigInt; } -public abstract interface class space/kscience/kmath/operations/BufferAlgebra : space/kscience/kmath/operations/Algebra { - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public fun buffer (I[Ljava/lang/Object;)Lspace/kscience/kmath/structures/Buffer; - public abstract fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra; - public fun getElementBufferFactory ()Lspace/kscience/kmath/structures/BufferFactory; - public fun map (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer; - public fun mapIndexed (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/structures/Buffer; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; - public fun zip (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/structures/Buffer; -} - -public final class space/kscience/kmath/operations/BufferAlgebraKt { - public static final fun acos (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun acosh (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun asin (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun asinh (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun atan (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun atanh (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun buffer (Lspace/kscience/kmath/operations/BufferAlgebra;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public static final fun buffer (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public static final fun buffer (Lspace/kscience/kmath/operations/BufferField;[Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer; - public static final fun cos (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun cosh (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun exp (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun getBufferAlgebra (Lspace/kscience/kmath/operations/Field;)Lspace/kscience/kmath/operations/BufferFieldOps; - public static final fun getBufferAlgebra (Lspace/kscience/kmath/operations/IntRing;)Lspace/kscience/kmath/operations/BufferRingOps; - public static final fun getBufferAlgebra (Lspace/kscience/kmath/operations/ShortRing;)Lspace/kscience/kmath/operations/BufferRingOps; - public static final fun ln (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun pow (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer; - public static final fun sin (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun sinh (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun tan (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun tanh (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun withSize (Lspace/kscience/kmath/operations/BufferFieldOps;I)Lspace/kscience/kmath/operations/BufferField; -} - -public final class space/kscience/kmath/operations/BufferExtensionsKt { - public static final fun asIterable (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Iterable; - public static final fun asSequence (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/sequences/Sequence; - public static final fun fold (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; - public static final fun foldIndexed (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; - public static final fun mapIndexedToBuffer (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer; - public static final fun mapToBuffer (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public static final fun reduce (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; - public static final fun toList (Lspace/kscience/kmath/structures/Buffer;)Ljava/util/List; -} - -public final class space/kscience/kmath/operations/BufferField : space/kscience/kmath/operations/BufferFieldOps, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/WithSize { - public fun (Lspace/kscience/kmath/operations/Field;I)V - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/structures/Buffer; - public fun getSize ()I - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/structures/Buffer; -} - -public class space/kscience/kmath/operations/BufferFieldOps : space/kscience/kmath/operations/BufferRingOps, space/kscience/kmath/operations/BufferAlgebra, space/kscience/kmath/operations/FieldOps, space/kscience/kmath/operations/ScaleOperations { - public fun (Lspace/kscience/kmath/operations/Field;)V - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/structures/Buffer;D)Lspace/kscience/kmath/structures/Buffer; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; -} - -public class space/kscience/kmath/operations/BufferRingOps : space/kscience/kmath/operations/BufferAlgebra, space/kscience/kmath/operations/RingOps { - public fun (Lspace/kscience/kmath/operations/Ring;)V - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra; - public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Ring; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public abstract interface class space/kscience/kmath/operations/BufferTransform { - public abstract fun transform (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; -} - public final class space/kscience/kmath/operations/ByteRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring { public static final field INSTANCE Lspace/kscience/kmath/operations/ByteRing; public fun add (BB)Ljava/lang/Byte; public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory; public fun getOne ()Ljava/lang/Byte; public synthetic fun getOne ()Ljava/lang/Object; public fun getZero ()Ljava/lang/Byte; @@ -1660,106 +1113,6 @@ public final class space/kscience/kmath/operations/ByteRing : space/kscience/kma public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; } -public final class space/kscience/kmath/operations/DoubleBufferField : space/kscience/kmath/operations/DoubleBufferOps, space/kscience/kmath/operations/ExtendedField { - public fun (I)V - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/structures/Buffer; - public final fun getSize ()I - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/structures/Buffer; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public synthetic fun power (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer; - public fun power-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)[D - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public abstract class space/kscience/kmath/operations/DoubleBufferOps : space/kscience/kmath/operations/BufferAlgebra, space/kscience/kmath/operations/ExtendedFieldOps, space/kscience/kmath/operations/Norm { - public static final field Companion Lspace/kscience/kmath/operations/DoubleBufferOps$Companion; - public fun ()V - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun exp-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra; - public fun getElementAlgebra ()Lspace/kscience/kmath/operations/DoubleField; - public synthetic fun getElementBufferFactory ()Lspace/kscience/kmath/structures/BufferFactory; - public fun getElementBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun ln-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun map (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer; - public final fun map-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;)[D - public synthetic fun mapIndexed (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/structures/Buffer; - public final fun mapIndexed-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)[D - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun minus-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object; - public fun norm (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Double; - public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun plus-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;D)[D - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; - public synthetic fun zip (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/structures/Buffer; - public final fun zip-XquIszc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)[D -} - -public final class space/kscience/kmath/operations/DoubleBufferOps$Companion : space/kscience/kmath/operations/DoubleBufferOps { -} - -public final class space/kscience/kmath/operations/DoubleBufferOpsKt { - public static final fun average (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;)D - public static final fun averageOf (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)D - public static final fun covariance (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)D - public static final fun dispersion (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;)D - public static final fun std (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;)D - public static final fun sum (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;)D - public static final fun sumOf (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)D -} - public final class space/kscience/kmath/operations/DoubleField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/ScaleOperations { public static final field INSTANCE Lspace/kscience/kmath/operations/DoubleField; public fun acos (D)Ljava/lang/Double; @@ -1787,7 +1140,6 @@ public final class space/kscience/kmath/operations/DoubleField : space/kscience/ public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun exp (D)Ljava/lang/Double; public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory; public fun getOne ()Ljava/lang/Double; public synthetic fun getOne ()Ljava/lang/Object; public fun getZero ()Ljava/lang/Double; @@ -1812,8 +1164,6 @@ public final class space/kscience/kmath/operations/DoubleField : space/kscience/ public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; public fun sinh (D)Ljava/lang/Double; public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sqrt (D)Ljava/lang/Double; - public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object; public fun tan (D)Ljava/lang/Double; public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; public fun tanh (D)Ljava/lang/Double; @@ -1824,12 +1174,6 @@ public final class space/kscience/kmath/operations/DoubleField : space/kscience/ public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; } -public final class space/kscience/kmath/operations/DoubleL2Norm : space/kscience/kmath/operations/Norm { - public static final field INSTANCE Lspace/kscience/kmath/operations/DoubleL2Norm; - public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object; - public fun norm (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Double; -} - public abstract interface class space/kscience/kmath/operations/ExponentialOperations : space/kscience/kmath/operations/Algebra { public static final field ACOSH_OPERATION Ljava/lang/String; public static final field ASINH_OPERATION Ljava/lang/String; @@ -1861,41 +1205,36 @@ public final class space/kscience/kmath/operations/ExponentialOperations$Compani public static final field TANH_OPERATION Ljava/lang/String; } -public abstract interface class space/kscience/kmath/operations/ExtendedField : space/kscience/kmath/operations/ExtendedFieldOps, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumericAlgebra { +public abstract interface class space/kscience/kmath/operations/ExtendedField : space/kscience/kmath/operations/ExtendedFieldOperations, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/ScaleOperations { public fun acosh (Ljava/lang/Object;)Ljava/lang/Object; public fun asinh (Ljava/lang/Object;)Ljava/lang/Object; public fun atanh (Ljava/lang/Object;)Ljava/lang/Object; + public fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; public fun cosh (Ljava/lang/Object;)Ljava/lang/Object; public fun rightSideNumberOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; public fun sinh (Ljava/lang/Object;)Ljava/lang/Object; public fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; } -public abstract interface class space/kscience/kmath/operations/ExtendedFieldOps : space/kscience/kmath/operations/ExponentialOperations, space/kscience/kmath/operations/FieldOps, space/kscience/kmath/operations/PowerOperations, space/kscience/kmath/operations/ScaleOperations, space/kscience/kmath/operations/TrigonometricOperations { +public abstract interface class space/kscience/kmath/operations/ExtendedFieldOperations : space/kscience/kmath/operations/ExponentialOperations, space/kscience/kmath/operations/FieldOperations, space/kscience/kmath/operations/PowerOperations, space/kscience/kmath/operations/TrigonometricOperations { public fun tan (Ljava/lang/Object;)Ljava/lang/Object; public fun tanh (Ljava/lang/Object;)Ljava/lang/Object; public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; } -public abstract interface class space/kscience/kmath/operations/Field : space/kscience/kmath/operations/FieldOps, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring, space/kscience/kmath/operations/ScaleOperations { - public static final field Companion Lspace/kscience/kmath/operations/Field$Companion; +public abstract interface class space/kscience/kmath/operations/Field : space/kscience/kmath/operations/FieldOperations, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring, space/kscience/kmath/operations/ScaleOperations { public fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Ljava/lang/Object;I)Ljava/lang/Object; } -public final class space/kscience/kmath/operations/Field$Companion { -} - -public abstract interface class space/kscience/kmath/operations/FieldOps : space/kscience/kmath/operations/RingOps { - public static final field Companion Lspace/kscience/kmath/operations/FieldOps$Companion; +public abstract interface class space/kscience/kmath/operations/FieldOperations : space/kscience/kmath/operations/RingOperations { + public static final field Companion Lspace/kscience/kmath/operations/FieldOperations$Companion; public static final field DIV_OPERATION Ljava/lang/String; public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; public fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; } -public final class space/kscience/kmath/operations/FieldOps$Companion { +public final class space/kscience/kmath/operations/FieldOperations$Companion { public static final field DIV_OPERATION Ljava/lang/String; } @@ -1926,7 +1265,6 @@ public final class space/kscience/kmath/operations/FloatField : space/kscience/k public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun exp (F)Ljava/lang/Float; public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory; public fun getOne ()Ljava/lang/Float; public synthetic fun getOne ()Ljava/lang/Object; public fun getZero ()Ljava/lang/Float; @@ -1951,8 +1289,6 @@ public final class space/kscience/kmath/operations/FloatField : space/kscience/k public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; public fun sinh (F)Ljava/lang/Float; public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sqrt (F)Ljava/lang/Float; - public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object; public fun tan (F)Ljava/lang/Float; public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; public fun tanh (F)Ljava/lang/Float; @@ -1963,12 +1299,12 @@ public final class space/kscience/kmath/operations/FloatField : space/kscience/k public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; } -public abstract interface class space/kscience/kmath/operations/Group : space/kscience/kmath/operations/GroupOps { +public abstract interface class space/kscience/kmath/operations/Group : space/kscience/kmath/operations/GroupOperations { public abstract fun getZero ()Ljava/lang/Object; } -public abstract interface class space/kscience/kmath/operations/GroupOps : space/kscience/kmath/operations/Algebra { - public static final field Companion Lspace/kscience/kmath/operations/GroupOps$Companion; +public abstract interface class space/kscience/kmath/operations/GroupOperations : space/kscience/kmath/operations/Algebra { + public static final field Companion Lspace/kscience/kmath/operations/GroupOperations$Companion; public static final field MINUS_OPERATION Ljava/lang/String; public static final field PLUS_OPERATION Ljava/lang/String; public abstract fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; @@ -1980,7 +1316,7 @@ public abstract interface class space/kscience/kmath/operations/GroupOps : space public fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object; } -public final class space/kscience/kmath/operations/GroupOps$Companion { +public final class space/kscience/kmath/operations/GroupOperations$Companion { public static final field MINUS_OPERATION Ljava/lang/String; public static final field PLUS_OPERATION Ljava/lang/String; } @@ -1989,7 +1325,6 @@ public final class space/kscience/kmath/operations/IntRing : space/kscience/kmat public static final field INSTANCE Lspace/kscience/kmath/operations/IntRing; public fun add (II)Ljava/lang/Integer; public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory; public fun getOne ()Ljava/lang/Integer; public synthetic fun getOne ()Ljava/lang/Object; public fun getZero ()Ljava/lang/Integer; @@ -2010,10 +1345,6 @@ public final class space/kscience/kmath/operations/IntRing : space/kscience/kmat public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; } -public final class space/kscience/kmath/operations/IsIntegerKt { - public static final fun isInteger (Ljava/lang/Number;)Z -} - public final class space/kscience/kmath/operations/JBigDecimalField : space/kscience/kmath/operations/JBigDecimalFieldBase { public static final field Companion Lspace/kscience/kmath/operations/JBigDecimalField$Companion; public fun ()V @@ -2068,16 +1399,13 @@ public final class space/kscience/kmath/operations/JBigIntegerField : space/ksci public fun unaryMinus (Ljava/math/BigInteger;)Ljava/math/BigInteger; } -public final class space/kscience/kmath/operations/LogicAlgebra$Companion { - public final fun getFALSE ()Lspace/kscience/kmath/expressions/Symbol; - public final fun getTRUE ()Lspace/kscience/kmath/expressions/Symbol; +public abstract interface annotation class space/kscience/kmath/operations/KMathContext : java/lang/annotation/Annotation { } public final class space/kscience/kmath/operations/LongRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring { public static final field INSTANCE Lspace/kscience/kmath/operations/LongRing; public fun add (JJ)Ljava/lang/Long; public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory; public fun getOne ()Ljava/lang/Long; public synthetic fun getOne ()Ljava/lang/Object; public fun getZero ()Ljava/lang/Long; @@ -2102,15 +1430,6 @@ public abstract interface class space/kscience/kmath/operations/Norm { public abstract fun norm (Ljava/lang/Object;)Ljava/lang/Object; } -public final class space/kscience/kmath/operations/NumbersKt { - public static final fun getAlgebra (Lkotlin/jvm/internal/ByteCompanionObject;)Lspace/kscience/kmath/operations/ByteRing; - public static final fun getAlgebra (Lkotlin/jvm/internal/DoubleCompanionObject;)Lspace/kscience/kmath/operations/DoubleField; - public static final fun getAlgebra (Lkotlin/jvm/internal/FloatCompanionObject;)Lspace/kscience/kmath/operations/FloatField; - public static final fun getAlgebra (Lkotlin/jvm/internal/IntCompanionObject;)Lspace/kscience/kmath/operations/IntRing; - public static final fun getAlgebra (Lkotlin/jvm/internal/LongCompanionObject;)Lspace/kscience/kmath/operations/LongRing; - public static final fun getAlgebra (Lkotlin/jvm/internal/ShortCompanionObject;)Lspace/kscience/kmath/operations/ShortRing; -} - public abstract interface class space/kscience/kmath/operations/NumericAlgebra : space/kscience/kmath/operations/Algebra { public fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; public fun leftSideNumberOperation (Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object; @@ -2125,7 +1444,10 @@ public final class space/kscience/kmath/operations/NumericAlgebraKt { public static final fun getPi (Lspace/kscience/kmath/operations/NumericAlgebra;)Ljava/lang/Object; } -public abstract interface class space/kscience/kmath/operations/PowerOperations : space/kscience/kmath/operations/FieldOps { +public final class space/kscience/kmath/operations/OptionalOperationsKt { +} + +public abstract interface class space/kscience/kmath/operations/PowerOperations : space/kscience/kmath/operations/Algebra { public static final field Companion Lspace/kscience/kmath/operations/PowerOperations$Companion; public static final field POW_OPERATION Ljava/lang/String; public static final field SQRT_OPERATION Ljava/lang/String; @@ -2139,24 +1461,19 @@ public final class space/kscience/kmath/operations/PowerOperations$Companion { public static final field SQRT_OPERATION Ljava/lang/String; } -public abstract interface class space/kscience/kmath/operations/Ring : space/kscience/kmath/operations/Group, space/kscience/kmath/operations/RingOps { - public static final field Companion Lspace/kscience/kmath/operations/Ring$Companion; +public abstract interface class space/kscience/kmath/operations/Ring : space/kscience/kmath/operations/Group, space/kscience/kmath/operations/RingOperations { public abstract fun getOne ()Ljava/lang/Object; - public fun power-Qn1smSk (Ljava/lang/Object;I)Ljava/lang/Object; } -public final class space/kscience/kmath/operations/Ring$Companion { -} - -public abstract interface class space/kscience/kmath/operations/RingOps : space/kscience/kmath/operations/GroupOps { - public static final field Companion Lspace/kscience/kmath/operations/RingOps$Companion; +public abstract interface class space/kscience/kmath/operations/RingOperations : space/kscience/kmath/operations/GroupOperations { + public static final field Companion Lspace/kscience/kmath/operations/RingOperations$Companion; public static final field TIMES_OPERATION Ljava/lang/String; public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; public abstract fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; } -public final class space/kscience/kmath/operations/RingOps$Companion { +public final class space/kscience/kmath/operations/RingOperations$Companion { public static final field TIMES_OPERATION Ljava/lang/String; } @@ -2171,7 +1488,6 @@ public final class space/kscience/kmath/operations/ShortRing : space/kscience/km public static final field INSTANCE Lspace/kscience/kmath/operations/ShortRing; public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun add (SS)Ljava/lang/Short; - public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory; public synthetic fun getOne ()Ljava/lang/Object; public fun getOne ()Ljava/lang/Short; public synthetic fun getZero ()Ljava/lang/Object; @@ -2217,10 +1533,6 @@ public final class space/kscience/kmath/operations/TrigonometricOperations$Compa public static final field TAN_OPERATION Ljava/lang/String; } -public abstract interface class space/kscience/kmath/operations/WithSize { - public abstract fun getSize ()I -} - public final class space/kscience/kmath/structures/ArrayBuffer : space/kscience/kmath/structures/MutableBuffer { public fun ([Ljava/lang/Object;)V public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; @@ -2228,118 +1540,38 @@ public final class space/kscience/kmath/structures/ArrayBuffer : space/kscience/ public fun getSize ()I public fun iterator ()Ljava/util/Iterator; public fun set (ILjava/lang/Object;)V - public fun toString ()Ljava/lang/String; } -public final class space/kscience/kmath/structures/ArrayBufferKt { - public static final fun asBuffer ([Ljava/lang/Object;)Lspace/kscience/kmath/structures/ArrayBuffer; -} - -public abstract interface class space/kscience/kmath/structures/Buffer : space/kscience/kmath/operations/WithSize { +public abstract interface class space/kscience/kmath/structures/Buffer { public static final field Companion Lspace/kscience/kmath/structures/Buffer$Companion; public abstract fun get (I)Ljava/lang/Object; public abstract fun getSize ()I - public fun iterator ()Ljava/util/Iterator; - public abstract fun toString ()Ljava/lang/String; + public abstract fun iterator ()Ljava/util/Iterator; } public final class space/kscience/kmath/structures/Buffer$Companion { public final fun auto (Lkotlin/reflect/KClass;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; public final fun boxing (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; public final fun contentEquals (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Z - public final fun toString (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/String; -} - -public final class space/kscience/kmath/structures/BufferExpanded : space/kscience/kmath/structures/BufferView { - public fun (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;II)V - public synthetic fun (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun get (I)Ljava/lang/Object; - public final fun getOffset ()I - public fun getOrigin ()Lspace/kscience/kmath/structures/Buffer; - public fun getSize ()I - public fun toString ()Ljava/lang/String; -} - -public abstract interface class space/kscience/kmath/structures/BufferFactory { - public static final field Companion Lspace/kscience/kmath/structures/BufferFactory$Companion; - public abstract fun invoke (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; -} - -public final class space/kscience/kmath/structures/BufferFactory$Companion { - public final fun boxing ()Lspace/kscience/kmath/structures/BufferFactory; } public final class space/kscience/kmath/structures/BufferKt { + public static final fun asBuffer (Ljava/util/List;)Lspace/kscience/kmath/structures/ListBuffer; + public static final fun asBuffer ([Ljava/lang/Object;)Lspace/kscience/kmath/structures/ArrayBuffer; + public static final fun asMutableBuffer (Ljava/util/List;)Ljava/util/List; public static final fun asReadOnly (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun first (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Object; - public static final fun get-Qn1smSk (Lspace/kscience/kmath/structures/Buffer;I)Ljava/lang/Object; public static final fun getIndices (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/ranges/IntRange; - public static final fun getOrNull (Lspace/kscience/kmath/structures/Buffer;I)Ljava/lang/Object; - public static final fun last (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Object; } -public final class space/kscience/kmath/structures/BufferPrimitiveAccessKt { +public final class space/kscience/kmath/structures/BufferOperationKt { + public static final fun asIterable (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Iterable; + public static final fun asSequence (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/sequences/Sequence; + public static final fun fold (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static final fun map (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; + public static final fun toList (Lspace/kscience/kmath/structures/Buffer;)Ljava/util/List; } -public final class space/kscience/kmath/structures/BufferSlice : space/kscience/kmath/structures/BufferView { - public fun (Lspace/kscience/kmath/structures/Buffer;II)V - public synthetic fun (Lspace/kscience/kmath/structures/Buffer;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun get (I)Ljava/lang/Object; - public final fun getOffset ()I - public fun getOrigin ()Lspace/kscience/kmath/structures/Buffer; - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; - public fun toString ()Ljava/lang/String; -} - -public abstract interface class space/kscience/kmath/structures/BufferView : space/kscience/kmath/structures/Buffer { - public fun get (I)Ljava/lang/Object; - public abstract fun getOrigin ()Lspace/kscience/kmath/structures/Buffer; -} - -public final class space/kscience/kmath/structures/BufferViewKt { - public static final fun expand (Lspace/kscience/kmath/structures/Buffer;Lkotlin/ranges/IntRange;Ljava/lang/Object;)Lspace/kscience/kmath/structures/BufferView; - public static final fun permute (Lspace/kscience/kmath/structures/Buffer;[I)Lspace/kscience/kmath/structures/PermutedBuffer; - public static final fun permute (Lspace/kscience/kmath/structures/MutableBuffer;[I)Lspace/kscience/kmath/structures/PermutedMutableBuffer; - public static final fun slice (Lspace/kscience/kmath/structures/Buffer;Lkotlin/ranges/IntRange;)Lspace/kscience/kmath/structures/BufferView; -} - -public final class space/kscience/kmath/structures/ByteBuffer : space/kscience/kmath/structures/MutableBuffer { - public static final synthetic fun box-impl ([B)Lspace/kscience/kmath/structures/ByteBuffer; - public static fun constructor-impl ([B)[B - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public static fun copy-impl ([B)Lspace/kscience/kmath/structures/MutableBuffer; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl ([BLjava/lang/Object;)Z - public static final fun equals-impl0 ([B[B)Z - public fun get (I)Ljava/lang/Byte; - public synthetic fun get (I)Ljava/lang/Object; - public static fun get-impl ([BI)Ljava/lang/Byte; - public final fun getArray ()[B - public fun getSize ()I - public static fun getSize-impl ([B)I - public fun hashCode ()I - public static fun hashCode-impl ([B)I - public synthetic fun iterator ()Ljava/util/Iterator; - public fun iterator ()Lkotlin/collections/ByteIterator; - public static fun iterator-impl ([B)Lkotlin/collections/ByteIterator; - public fun set (IB)V - public synthetic fun set (ILjava/lang/Object;)V - public static fun set-impl ([BIB)V - public fun toString ()Ljava/lang/String; - public static fun toString-impl ([B)Ljava/lang/String; - public final synthetic fun unbox-impl ()[B -} - -public final class space/kscience/kmath/structures/ByteBufferKt { - public static final fun ByteBuffer (ILkotlin/jvm/functions/Function1;)[B - public static final fun ByteBuffer ([B)[B - public static final fun asBuffer ([B)[B - public static final fun toByteArray (Lspace/kscience/kmath/structures/Buffer;)[B -} - -public final class space/kscience/kmath/structures/DoubleBuffer : space/kscience/kmath/structures/PrimitiveBuffer { - public static final field Companion Lspace/kscience/kmath/structures/DoubleBuffer$Companion; +public final class space/kscience/kmath/structures/DoubleBuffer : space/kscience/kmath/structures/MutableBuffer { public static final synthetic fun box-impl ([D)Lspace/kscience/kmath/structures/DoubleBuffer; public static fun constructor-impl ([D)[D public synthetic fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; @@ -2367,22 +1599,105 @@ public final class space/kscience/kmath/structures/DoubleBuffer : space/kscience public final synthetic fun unbox-impl ()[D } -public final class space/kscience/kmath/structures/DoubleBuffer$Companion { - public final fun zero-Udx-57Q (I)[D +public final class space/kscience/kmath/structures/DoubleBufferField : space/kscience/kmath/operations/ExtendedField { + public fun (I)V + public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; + public fun acos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; + public fun acosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun add-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; + public fun asin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; + public fun asinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; + public fun atan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; + public fun atanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; + public fun cos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; + public fun cosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun divide-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; + public fun exp-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun getOne ()Ljava/lang/Object; + public fun getOne ()Lspace/kscience/kmath/structures/Buffer; + public final fun getSize ()I + public synthetic fun getZero ()Ljava/lang/Object; + public fun getZero ()Lspace/kscience/kmath/structures/Buffer; + public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; + public fun ln-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun multiply-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; + public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer; + public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; + public fun power-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)[D + public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; + public fun scale-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;D)[D + public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; + public fun sin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; + public fun sinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; + public fun tan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; + public fun tanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; + public fun unaryMinus (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; +} + +public final class space/kscience/kmath/structures/DoubleBufferFieldOperations : space/kscience/kmath/operations/ExtendedFieldOperations { + public static final field INSTANCE Lspace/kscience/kmath/structures/DoubleBufferFieldOperations; + public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; + public fun acos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; + public fun acosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun add-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; + public fun asin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; + public fun asinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; + public fun atan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; + public fun atanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; + public fun cos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; + public fun cosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun divide-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; + public fun exp-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; + public fun ln-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun multiply-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; + public fun power-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)[D + public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; + public fun sin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; + public fun sinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; + public fun tan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; + public fun tanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D + public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; + public fun unaryMinus-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D } public final class space/kscience/kmath/structures/DoubleBufferKt { public static final fun DoubleBuffer (ILkotlin/jvm/functions/Function1;)[D public static final fun DoubleBuffer ([D)[D public static final fun asBuffer ([D)[D + public static final fun contentEquals-2c9zdjM ([D[D)Z public static final fun toDoubleArray (Lspace/kscience/kmath/structures/Buffer;)[D - public static final fun toDoubleBuffer (Lspace/kscience/kmath/structures/Buffer;)[D -} - -public abstract interface class space/kscience/kmath/structures/DoubleBufferTransform : space/kscience/kmath/operations/BufferTransform { - public synthetic fun transform (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public abstract fun transform-7Zdoou4 ([D)[D - public fun transform-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D } public abstract interface class space/kscience/kmath/structures/FlaggedBuffer : space/kscience/kmath/structures/Buffer { @@ -2405,10 +1720,9 @@ public final class space/kscience/kmath/structures/FlaggedDoubleBuffer : space/k public fun getSize ()I public final fun getValues ()[D public fun iterator ()Ljava/util/Iterator; - public fun toString ()Ljava/lang/String; } -public final class space/kscience/kmath/structures/FloatBuffer : space/kscience/kmath/structures/PrimitiveBuffer { +public final class space/kscience/kmath/structures/FloatBuffer : space/kscience/kmath/structures/MutableBuffer { public static final synthetic fun box-impl ([F)Lspace/kscience/kmath/structures/FloatBuffer; public static fun constructor-impl ([F)[F public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; @@ -2442,12 +1756,11 @@ public final class space/kscience/kmath/structures/FloatBufferKt { public static final fun toFloatArray (Lspace/kscience/kmath/structures/Buffer;)[F } -public final class space/kscience/kmath/structures/IntBuffer : space/kscience/kmath/structures/PrimitiveBuffer { +public final class space/kscience/kmath/structures/IntBuffer : space/kscience/kmath/structures/MutableBuffer { public static final synthetic fun box-impl ([I)Lspace/kscience/kmath/structures/IntBuffer; public static fun constructor-impl ([I)[I - public synthetic fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun copy-ir4F4A8 ()[I - public static fun copy-ir4F4A8 ([I)[I + public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; + public static fun copy-impl ([I)Lspace/kscience/kmath/structures/MutableBuffer; public fun equals (Ljava/lang/Object;)Z public static fun equals-impl ([ILjava/lang/Object;)Z public static final fun equals-impl0 ([I[I)Z @@ -2484,15 +1797,9 @@ public final class space/kscience/kmath/structures/ListBuffer : space/kscience/k public final fun getList ()Ljava/util/List; public fun getSize ()I public fun iterator ()Ljava/util/Iterator; - public fun toString ()Ljava/lang/String; } -public final class space/kscience/kmath/structures/ListBufferKt { - public static final fun asBuffer (Ljava/util/List;)Lspace/kscience/kmath/structures/ListBuffer; - public static final fun asMutableBuffer (Ljava/util/List;)Ljava/util/List; -} - -public final class space/kscience/kmath/structures/LongBuffer : space/kscience/kmath/structures/PrimitiveBuffer { +public final class space/kscience/kmath/structures/LongBuffer : space/kscience/kmath/structures/MutableBuffer { public static final synthetic fun box-impl ([J)Lspace/kscience/kmath/structures/LongBuffer; public static fun constructor-impl ([J)[J public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; @@ -2534,7 +1841,6 @@ public class space/kscience/kmath/structures/MemoryBuffer : space/kscience/kmath public fun getSize ()I protected final fun getSpec ()Lspace/kscience/kmath/memory/MemorySpec; public fun iterator ()Ljava/util/Iterator; - public fun toString ()Ljava/lang/String; } public final class space/kscience/kmath/structures/MemoryBuffer$Companion { @@ -2558,15 +1864,6 @@ public final class space/kscience/kmath/structures/MutableBuffer$Companion { public final fun short-1yRgbGw (ILkotlin/jvm/functions/Function1;)[S } -public abstract interface class space/kscience/kmath/structures/MutableBufferFactory : space/kscience/kmath/structures/BufferFactory { - public static final field Companion Lspace/kscience/kmath/structures/MutableBufferFactory$Companion; - public abstract fun invoke (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer; -} - -public final class space/kscience/kmath/structures/MutableBufferFactory$Companion { - public final fun boxing ()Lspace/kscience/kmath/structures/MutableBufferFactory; -} - public final class space/kscience/kmath/structures/MutableListBuffer : space/kscience/kmath/structures/MutableBuffer { public static final synthetic fun box-impl (Ljava/util/List;)Lspace/kscience/kmath/structures/MutableListBuffer; public static fun constructor-impl (ILkotlin/jvm/functions/Function1;)Ljava/util/List; @@ -2604,30 +1901,6 @@ public final class space/kscience/kmath/structures/MutableMemoryBuffer$Companion public final fun create (Lspace/kscience/kmath/memory/MemorySpec;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableMemoryBuffer; } -public final class space/kscience/kmath/structures/PermutedBuffer : space/kscience/kmath/structures/BufferView { - public fun (Lspace/kscience/kmath/structures/Buffer;[I)V - public fun get (I)Ljava/lang/Object; - public fun getOrigin ()Lspace/kscience/kmath/structures/Buffer; - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; - public fun toString ()Ljava/lang/String; -} - -public final class space/kscience/kmath/structures/PermutedMutableBuffer : space/kscience/kmath/structures/BufferView, space/kscience/kmath/structures/MutableBuffer { - public fun (Lspace/kscience/kmath/structures/MutableBuffer;[I)V - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun get (I)Ljava/lang/Object; - public synthetic fun getOrigin ()Lspace/kscience/kmath/structures/Buffer; - public fun getOrigin ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; - public fun set (ILjava/lang/Object;)V - public fun toString ()Ljava/lang/String; -} - -public abstract interface class space/kscience/kmath/structures/PrimitiveBuffer : space/kscience/kmath/structures/MutableBuffer { -} - public final class space/kscience/kmath/structures/ReadOnlyBuffer : space/kscience/kmath/structures/Buffer { public static final synthetic fun box-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Lspace/kscience/kmath/structures/ReadOnlyBuffer; public static fun constructor-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Lspace/kscience/kmath/structures/MutableBuffer; @@ -2697,6 +1970,5 @@ public final class space/kscience/kmath/structures/VirtualBuffer : space/kscienc public fun get (I)Ljava/lang/Object; public fun getSize ()I public fun iterator ()Ljava/util/Iterator; - public fun toString ()Ljava/lang/String; } diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 8c622e8b0..df70aa40b 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -1,80 +1,76 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity + plugins { - id("space.kscience.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } -kscience{ - jvm() - js() - native() - wasm{ - browser { - testTask { - useKarma { - webpackConfig.experiments.add("topLevelAwait") - useChromeHeadless() - } - } - } - } - - wasmTest{ +kotlin.sourceSets { + commonMain { dependencies { - implementation(kotlin("test")) + api(project(":kmath-memory")) } } - - dependencies { - api(projects.kmathMemory) - } - - testDependencies { - implementation(projects.testUtils) - } } readme { description = "Core classes, algebra definitions, basic linear algebra" - maturity = space.kscience.gradle.Maturity.DEVELOPMENT + maturity = Maturity.DEVELOPMENT propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( id = "algebras", - ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt", - ) { "Algebraic structures like rings, spaces and fields." } + description = """ + Algebraic structures like rings, spaces and fields. + """.trimIndent(), + ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt" + ) feature( id = "nd", - ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt", - ) { "Many-dimensional structures and operations on them." } + description = "Many-dimensional structures and operations on them.", + ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt" + ) feature( id = "linear", - ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt", - ) { "Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition." } + description = """ + Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition. + """.trimIndent(), + ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt" + ) feature( id = "buffers", - ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt", - ) { "One-dimensional structure" } + description = "One-dimensional structure", + ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt" + ) feature( id = "expressions", - ref = "src/commonMain/kotlin/space/kscience/kmath/expressions" - ) { - """ + description = """ By writing a single mathematical expression once, users will be able to apply different types of objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high performance calculations to code generation. - """.trimIndent() - } + """.trimIndent(), + ref = "src/commonMain/kotlin/space/kscience/kmath/expressions" + ) feature( id = "domains", - ref = "src/commonMain/kotlin/space/kscience/kmath/domains", - ) { "Domains" } + description = "Domains", + ref = "src/commonMain/kotlin/space/kscience/kmath/domains" + ) feature( - id = "autodiff", + id = "autodif", + description = "Automatic differentiation", ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt" - ) { "Automatic differentiation" } + ) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt index 49e2ee8d0..abbb46583 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt @@ -1,13 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.data -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.structures.Buffer @@ -19,20 +18,13 @@ import space.kscience.kmath.structures.Buffer public interface ColumnarData { public val size: Int - /** - * Provide a column by symbol or null if column with given symbol is not defined - */ - public operator fun get(symbol: Symbol): Buffer? + public operator fun get(symbol: Symbol): Buffer } -@UnstableKMathAPI -public val ColumnarData<*>.indices: IntRange get() = 0 until size - /** * A zero-copy method to represent a [Structure2D] as a two-column x-y data. * There could more than two columns in the structure. */ -@OptIn(PerformancePitfall::class) @UnstableKMathAPI public fun Structure2D.asColumnarData(mapping: Map): ColumnarData { require(shape[1] >= mapping.maxOf { it.value }) { "Column index out of bounds" } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt index de7e6f79b..663908e90 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt @@ -1,13 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.data -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.structures.Buffer import kotlin.math.max @@ -16,7 +15,7 @@ import kotlin.math.max * The buffer of X values. */ @UnstableKMathAPI -public interface XYColumnarData : ColumnarData { +public interface XYColumnarData : ColumnarData { /** * The buffer of X values */ @@ -27,53 +26,29 @@ public interface XYColumnarData : ColumnarData { */ public val y: Buffer - override fun get(symbol: Symbol): Buffer? = when (symbol) { + override fun get(symbol: Symbol): Buffer = when (symbol) { Symbol.x -> x Symbol.y -> y - else -> null - } - - public companion object{ - @UnstableKMathAPI - public fun of(x: Buffer, y: Buffer): XYColumnarData { - require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } - return object : XYColumnarData { - override val size: Int = x.size - override val x: Buffer = x - override val y: Buffer = y - } - } + else -> error("A column for symbol $symbol not found") } } - -/** - * Represent a [ColumnarData] as an [XYColumnarData]. The presence or respective columns is checked on creation. - */ +@Suppress("FunctionName") @UnstableKMathAPI -public fun ColumnarData.asXYData( - xSymbol: Symbol, - ySymbol: Symbol, -): XYColumnarData = object : XYColumnarData { - init { - requireNotNull(this@asXYData[xSymbol]){"The column with name $xSymbol is not present in $this"} - requireNotNull(this@asXYData[ySymbol]){"The column with name $ySymbol is not present in $this"} - } - override val size: Int get() = this@asXYData.size - override val x: Buffer get() = this@asXYData[xSymbol]!! - override val y: Buffer get() = this@asXYData[ySymbol]!! - override fun get(symbol: Symbol): Buffer? = when (symbol) { - Symbol.x -> x - Symbol.y -> y - else -> this@asXYData.get(symbol) +public fun XYColumnarData(x: Buffer, y: Buffer): XYColumnarData { + require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } + return object : XYColumnarData { + override val size: Int = x.size + override val x: Buffer = x + override val y: Buffer = y } } + /** * A zero-copy method to represent a [Structure2D] as a two-column x-y data. * There could more than two columns in the structure. */ -@OptIn(PerformancePitfall::class) @UnstableKMathAPI public fun Structure2D.asXYData(xIndex: Int = 0, yIndex: Int = 1): XYColumnarData { require(shape[1] >= max(xIndex, yIndex)) { "Column index out of bounds" } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt deleted file mode 100644 index 797a25443..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.data - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.structures.Buffer - - -/** - * A [ColumnarData] with additional [Symbol.yError] column for an [Symbol.y] error - * Inherits [XYColumnarData]. - */ -@UnstableKMathAPI -public interface XYErrorColumnarData : XYColumnarData { - public val yErr: Buffer - - override fun get(symbol: Symbol): Buffer = when (symbol) { - Symbol.x -> x - Symbol.y -> y - Symbol.yError -> yErr - else -> error("A column for symbol $symbol not found") - } - - public companion object { - public fun of( - x: Buffer, y: Buffer, yErr: Buffer - ): XYErrorColumnarData { - require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } - require(y.size == yErr.size) { "Buffer size mismatch. y buffer size is ${x.size}, yErr buffer size is ${y.size}" } - - return object : XYErrorColumnarData { - override val size: Int = x.size - override val x: Buffer = x - override val y: Buffer = y - override val yErr: Buffer = yErr - } - } - } -} - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt index 846bbad62..d76a44e9e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt @@ -1,26 +1,26 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.data -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer /** - * A [ColumnarData] with guaranteed [x], [y] and [z] columns designated by corresponding symbols. + * A [XYColumnarData] with guaranteed [x], [y] and [z] columns designated by corresponding symbols. * Inherits [XYColumnarData]. */ @UnstableKMathAPI -public interface XYZColumnarData : XYColumnarData { +public interface XYZColumnarData : XYColumnarData { public val z: Buffer - override fun get(symbol: Symbol): Buffer? = when (symbol) { + override fun get(symbol: Symbol): Buffer = when (symbol) { Symbol.x -> x Symbol.y -> y Symbol.z -> z - else -> null + else -> error("A column for symbol $symbol not found") } -} +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt index eecdcebad..e6e703cbf 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -12,7 +12,7 @@ import space.kscience.kmath.linear.Point * * @param T the type of element of this domain. */ -public interface Domain { +public interface Domain { /** * Checks if the specified point is contained in this domain. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt deleted file mode 100644 index d619883b4..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.domains - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.linear.Point - -@UnstableKMathAPI -public abstract class Domain1D>(public val range: ClosedRange) : Domain { - override val dimension: Int get() = 1 - - public operator fun contains(value: T): Boolean = range.contains(value) - - override operator fun contains(point: Point): Boolean { - require(point.size == 0) - return contains(point[0]) - } -} - -@UnstableKMathAPI -public class DoubleDomain1D( - @Suppress("CanBeParameter") public val doubleRange: ClosedFloatingPointRange, -) : Domain1D(doubleRange), DoubleDomain { - override fun getLowerBound(num: Int): Double { - require(num == 0) - return range.start - } - - override fun getUpperBound(num: Int): Double { - require(num == 0) - return range.endInclusive - } - - override fun volume(): Double = range.endInclusive - range.start - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as DoubleDomain1D - - if (doubleRange != other.doubleRange) return false - - return true - } - - override fun hashCode(): Int = doubleRange.hashCode() - - override fun toString(): String = doubleRange.toString() - - -} - -@UnstableKMathAPI -public val Domain1D.center: Double - get() = (range.endInclusive + range.start) / 2 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt index e56173624..ee1bebde0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt @@ -1,10 +1,10 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.domains -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI /** * n-dimensional volume diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt index 1049a251a..f5560d935 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt @@ -1,43 +1,33 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.domains -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.indices /** - * A hyper-square (or hyper-cube) real-space domain. It is formed by a [Buffer] of [lower] boundaries - * and a [Buffer] of upper boundaries. Upper should be greater or equals than lower. + * + * HyperSquareDomain class. + * + * @author Alexander Nozik */ @UnstableKMathAPI -public class HyperSquareDomain(public val lower: Buffer, public val upper: Buffer) : DoubleDomain { - init { - require(lower.size == upper.size) { - "Domain borders size mismatch. Lower borders size is ${lower.size}, but upper borders size is ${upper.size}." - } - require(lower.indices.all { lower[it] <= upper[it] }) { - "Domain borders order mismatch. Lower borders must be less or equals than upper borders." - } - } +public class HyperSquareDomain(private val lower: Buffer, private val upper: Buffer) : DoubleDomain { + public override val dimension: Int get() = lower.size - override val dimension: Int get() = lower.size - - public val center: DoubleBuffer get() = DoubleBuffer(dimension) { (lower[it] + upper[it]) / 2.0 } - - override operator fun contains(point: Point): Boolean = point.indices.all { i -> + public override operator fun contains(point: Point): Boolean = point.indices.all { i -> point[i] in lower[i]..upper[i] } - override fun getLowerBound(num: Int): Double = lower[num] + public override fun getLowerBound(num: Int): Double = lower[num] - override fun getUpperBound(num: Int): Double = upper[num] + public override fun getUpperBound(num: Int): Double = upper[num] - override fun volume(): Double { + public override fun volume(): Double { var res = 1.0 for (i in 0 until dimension) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt index 5351a295d..7ffc0659d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt @@ -1,19 +1,19 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.domains -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.UnstableKMathAPI @UnstableKMathAPI -public class UnconstrainedDomain(override val dimension: Int) : DoubleDomain { - override operator fun contains(point: Point): Boolean = true +public class UnconstrainedDomain(public override val dimension: Int) : DoubleDomain { + public override operator fun contains(point: Point): Boolean = true - override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY + public override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY - override fun getUpperBound(num: Int): Double = Double.POSITIVE_INFINITY + public override fun getUpperBound(num: Int): Double = Double.POSITIVE_INFINITY - override fun volume(): Double = Double.POSITIVE_INFINITY + public override fun volume(): Double = Double.POSITIVE_INFINITY } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt new file mode 100644 index 000000000..e7acada85 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.domains + +import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.UnstableKMathAPI + +@UnstableKMathAPI +public class UnivariateDomain(public val range: ClosedFloatingPointRange) : DoubleDomain { + public override val dimension: Int get() = 1 + + public operator fun contains(d: Double): Boolean = range.contains(d) + + public override operator fun contains(point: Point): Boolean { + require(point.size == 0) + return contains(point[0]) + } + + public override fun getLowerBound(num: Int): Double { + require(num == 0) + return range.start + } + + public override fun getUpperBound(num: Int): Double { + require(num == 0) + return range.endInclusive + } + + public override fun volume(): Double = range.endInclusive - range.start +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt deleted file mode 100644 index 8c7cb0cf1..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableBufferFactory -import space.kscience.kmath.structures.asBuffer -import kotlin.math.max -import kotlin.math.min - -/** - * Class representing both the value and the differentials of a function. - * - * This class is the workhorse of the differentiation package. - * - * This class is an implementation of the extension to Rall's numbers described in Dan Kalman's paper - * [Doubly Recursive Multivariate Automatic Differentiation](http://www1.american.edu/cas/mathstat/People/kalman/pdffiles/mmgautodiff.pdf), - * Mathematics Magazine, vol. 75, no. 3, June 2002. Rall's numbers are an extension to the real numbers used - * throughout mathematical expressions; they hold the derivative together with the value of a function. Dan Kalman's - * derivative structures hold all partial derivatives up to any specified order, with respect to any number of free - * parameters. Rall's numbers therefore can be seen as derivative structures for order one derivative and one free - * parameter, and real numbers can be seen as derivative structures with zero order derivative and no free parameters. - * - * Derived from - * [Commons Math's `DerivativeStructure`](https://github.com/apache/commons-math/blob/924f6c357465b39beb50e3c916d5eb6662194175/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/differentiation/DerivativeStructure.java). - */ -@UnstableKMathAPI -public interface DS> { - public val derivativeAlgebra: DSAlgebra - public val data: Buffer -} - -/** - * Get a partial derivative. - * - * @param orders derivation orders with respect to each variable (if all orders are 0, the value is returned). - * @return partial derivative. - * @see value - */ -@UnstableKMathAPI -private fun > DS.getPartialDerivative(vararg orders: Int): T = - data[derivativeAlgebra.compiler.getPartialDerivativeIndex(*orders)] - -/** - * Provide a partial derivative with given symbols. On symbol could me mentioned multiple times - */ -@UnstableKMathAPI -public fun > DS.derivative(symbols: List): T { - require(symbols.size <= derivativeAlgebra.order) { "The order of derivative ${symbols.size} exceeds computed order ${derivativeAlgebra.order}" } - val ordersCount: Map = symbols.map { it.identity }.groupBy { it }.mapValues { it.value.size } - return getPartialDerivative(*symbols.map { ordersCount[it] ?: 0 }.toIntArray()) -} - -/** - * Provide a partial derivative with given symbols. On symbol could me mentioned multiple times - */ -@UnstableKMathAPI -public fun > DS.derivative(vararg symbols: Symbol): T { - require(symbols.size <= derivativeAlgebra.order) { "The order of derivative ${symbols.size} exceeds computed order ${derivativeAlgebra.order}" } - val ordersCount: Map = symbols.map { it.identity }.groupBy { it }.mapValues { it.value.size } - return getPartialDerivative(*symbols.map { ordersCount[it] ?: 0 }.toIntArray()) -} - -/** - * The value part of the derivative structure. - * - * @see getPartialDerivative - */ -@UnstableKMathAPI -public val > DS.value: T get() = data[0] - -@UnstableKMathAPI -public abstract class DSAlgebra>( - public val algebra: A, - public val order: Int, - bindings: Map, -) : ExpressionAlgebra>, SymbolIndexer { - - /** - * Get the compiler for number of free parameters and order. - * - * @return cached rules set. - */ - @PublishedApi - internal val compiler: DSCompiler by lazy { - val numberOfVariables = bindings.size - // get the cached compilers - val cache: Array?>>? = null - - // we need to create more compilers - val maxParameters: Int = max(numberOfVariables, cache?.size ?: 0) - val maxOrder: Int = max(order, if (cache == null) 0 else cache[0].size) - val newCache: Array?>> = Array(maxParameters + 1) { arrayOfNulls(maxOrder + 1) } - - if (cache != null) { - // preserve the already created compilers - for (i in cache.indices) { - cache[i].copyInto(newCache[i], endIndex = cache[i].size) - } - } - - // create the array in increasing diagonal order - for (diag in 0..numberOfVariables + order) { - for (o in max(0, diag - numberOfVariables)..min(order, diag)) { - val p: Int = diag - o - if (newCache[p][o] == null) { - val valueCompiler: DSCompiler? = if (p == 0) null else newCache[p - 1][o]!! - val derivativeCompiler: DSCompiler? = if (o == 0) null else newCache[p][o - 1]!! - - newCache[p][o] = DSCompiler( - algebra, - p, - o, - valueCompiler, - derivativeCompiler, - ) - } - } - } - - return@lazy newCache[numberOfVariables][order]!! - } - - private val variables: Map by lazy { - bindings.entries.mapIndexed { index, (key, value) -> - key to DSSymbol( - index, - key, - value, - ) - }.toMap() - } - override val symbols: List = bindings.map { it.key } - - private fun bufferForVariable(index: Int, value: T): Buffer { - val buffer = algebra.bufferFactory(compiler.size) { algebra.zero } - buffer[0] = value - if (compiler.order > 0) { - // the derivative of the variable with respect to itself is 1. - - val indexOfDerivative = compiler.getPartialDerivativeIndex(*IntArray(symbols.size).apply { - set(index, 1) - }) - - buffer[indexOfDerivative] = algebra.one - } - return buffer - } - - @UnstableKMathAPI - private inner class DSImpl( - override val data: Buffer, - ) : DS { - override val derivativeAlgebra: DSAlgebra get() = this@DSAlgebra - } - - protected fun DS(data: Buffer): DS = DSImpl(data) - - - /** - * Build an instance representing a variable. - * - * Instances built using this constructor are considered to be the free variables with respect to which - * differentials are computed. As such, their differential with respect to themselves is +1. - */ - public fun variable( - index: Int, - value: T, - ): DS { - require(index < compiler.freeParameters) { "number is too large: $index >= ${compiler.freeParameters}" } - return DS(bufferForVariable(index, value)) - } - - /** - * Build an instance from all its derivatives. - * - * @param derivatives derivatives sorted according to [DSCompiler.getPartialDerivativeIndex]. - */ - public fun ofDerivatives( - vararg derivatives: T, - ): DS { - require(derivatives.size == compiler.size) { "dimension mismatch: ${derivatives.size} and ${compiler.size}" } - val data = derivatives.asBuffer() - - return DS(data) - } - - /** - * A class implementing both [DS] and [Symbol]. - */ - @UnstableKMathAPI - public inner class DSSymbol internal constructor( - index: Int, - symbol: Symbol, - value: T, - ) : Symbol by symbol, DS { - override val derivativeAlgebra: DSAlgebra get() = this@DSAlgebra - override val data: Buffer = bufferForVariable(index, value) - } - - public override fun const(value: T): DS { - val buffer = algebra.bufferFactory(compiler.size) { algebra.zero } - buffer[0] = value - - return DS(buffer) - } - - override fun bindSymbolOrNull(value: String): DSSymbol? = variables[StringSymbol(value)] - - override fun bindSymbol(value: String): DSSymbol = - bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this") - - public fun bindSymbolOrNull(symbol: Symbol): DSSymbol? = variables[symbol.identity] - - public fun bindSymbol(symbol: Symbol): DSSymbol = - bindSymbolOrNull(symbol.identity) ?: error("Symbol '${symbol}' is not supported in $this") - - public fun DS.derivative(symbols: List): T { - require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" } - val ordersCount = symbols.groupBy { it }.mapValues { it.value.size } - return getPartialDerivative(*variables.keys.map { ordersCount[it] ?: 0 }.toIntArray()) - } - - public fun DS.derivative(vararg symbols: Symbol): T = derivative(symbols.toList()) - -} - - -/** - * A ring over [DS]. - * - * @property order The derivation order. - * @param bindings The map of bindings values. All bindings are considered free parameters. - */ -@UnstableKMathAPI -public open class DSRing( - algebra: A, - order: Int, - bindings: Map, -) : DSAlgebra(algebra, order, bindings), - Ring>, - ScaleOperations>, - NumericAlgebra>, - NumbersAddOps> - where A : Ring, A : NumericAlgebra, A : ScaleOperations { - - public val elementBufferFactory: MutableBufferFactory = algebra.bufferFactory - - override fun bindSymbolOrNull(value: String): DSSymbol? = - super.bindSymbolOrNull(value) - - override fun DS.unaryMinus(): DS = mapData { -it } - - /** - * Create a copy of given [Buffer] and modify it according to [block] - */ - protected inline fun DS.transformDataBuffer(block: A.(MutableBuffer) -> Unit): DS { - require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - val newData = elementBufferFactory(compiler.size) { data[it] } - algebra.block(newData) - return DS(newData) - } - - protected fun DS.mapData(block: A.(T) -> T): DS { - require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - val newData: Buffer = data.mapToBuffer(elementBufferFactory) { - algebra.block(it) - } - return DS(newData) - } - - protected fun DS.mapDataIndexed(block: (Int, T) -> T): DS { - require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - val newData: Buffer = data.mapIndexedToBuffer(elementBufferFactory, block) - return DS(newData) - } - - override val zero: DS by lazy { - const(algebra.zero) - } - - override val one: DS by lazy { - const(algebra.one) - } - - override fun number(value: Number): DS = const(algebra.number(value)) - - override fun add(left: DS, right: DS): DS = left.transformDataBuffer { result -> - require(right.derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - compiler.add(left.data, 0, right.data, 0, result, 0) - } - - override fun scale(a: DS, value: Double): DS = a.mapData { - it.times(value) - } - - override fun multiply( - left: DS, - right: DS, - ): DS = left.transformDataBuffer { result -> - compiler.multiply(left.data, 0, right.data, 0, result, 0) - } -// -// override fun DS.minus(arg: DS): DS = transformDataBuffer { result -> -// subtract(data, 0, arg.data, 0, result, 0) -// } - - override operator fun DS.plus(other: Number): DS = transformDataBuffer { - it[0] += number(other) - } - -// -// override operator fun DS.minus(other: Number): DS = -// this + (-other.toDouble()) - - override operator fun Number.plus(other: DS): DS = other + this - override operator fun Number.minus(other: DS): DS = other - this -} - -@UnstableKMathAPI -public class DerivativeStructureRingExpression( - public val algebra: A, - public val elementBufferFactory: MutableBufferFactory = algebra.bufferFactory, - public val function: DSRing.() -> DS, -) : DifferentiableExpression where A : Ring, A : ScaleOperations, A : NumericAlgebra { - override operator fun invoke(arguments: Map): T = - DSRing(algebra, 0, arguments).function().value - - override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> - with( - DSRing( - algebra, - symbols.size, - arguments - ) - ) { function().derivative(symbols) } - } -} - -/** - * A field over [DS]. - * - * @property order The derivation order. - * @param bindings The map of bindings values. All bindings are considered free parameters. - */ -@UnstableKMathAPI -public class DSField>( - algebra: A, - order: Int, - bindings: Map, -) : DSRing(algebra, order, bindings), ExtendedField> { - override fun number(value: Number): DS = const(algebra.number(value)) - - override fun divide(left: DS, right: DS): DS = left.transformDataBuffer { result -> - compiler.divide(left.data, 0, right.data, 0, result, 0) - } - - override fun sin(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.sin(arg.data, 0, result, 0) - } - - override fun cos(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.cos(arg.data, 0, result, 0) - } - - override fun tan(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.tan(arg.data, 0, result, 0) - } - - override fun asin(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.asin(arg.data, 0, result, 0) - } - - override fun acos(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.acos(arg.data, 0, result, 0) - } - - override fun atan(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.atan(arg.data, 0, result, 0) - } - - override fun sinh(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.sinh(arg.data, 0, result, 0) - } - - override fun cosh(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.cosh(arg.data, 0, result, 0) - } - - override fun tanh(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.tanh(arg.data, 0, result, 0) - } - - override fun asinh(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.asinh(arg.data, 0, result, 0) - } - - override fun acosh(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.acosh(arg.data, 0, result, 0) - } - - override fun atanh(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.atanh(arg.data, 0, result, 0) - } - - override fun power(arg: DS, pow: Number): DS = when (pow) { - is Int -> arg.transformDataBuffer { result -> - compiler.pow(arg.data, 0, pow, result, 0) - } - - else -> arg.transformDataBuffer { result -> - compiler.pow(arg.data, 0, pow.toDouble(), result, 0) - } - } - - override fun sqrt(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.sqrt(arg.data, 0, result, 0) - } - - public fun power(arg: DS, pow: DS): DS = arg.transformDataBuffer { result -> - compiler.pow(arg.data, 0, pow.data, 0, result, 0) - } - - override fun exp(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.exp(arg.data, 0, result, 0) - } - - override fun ln(arg: DS): DS = arg.transformDataBuffer { result -> - compiler.ln(arg.data, 0, result, 0) - } -} - -@UnstableKMathAPI -public class DSFieldExpression>( - public val algebra: A, - public val function: DSField.() -> DS, -) : DifferentiableExpression { - override operator fun invoke(arguments: Map): T = - DSField(algebra, 0, arguments).function().value - - override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> - DSField( - algebra, - symbols.size, - arguments, - ).run { function().derivative(symbols) } - } -} - - -@UnstableKMathAPI -public class DSFieldProcessor>( - public val algebra: A, -) : AutoDiffProcessor, DSField> { - override fun differentiate( - function: DSField.() -> DS, - ): DifferentiableExpression = DSFieldExpression(algebra, function) -} - -@UnstableKMathAPI -public val Double.Companion.autodiff: DSFieldProcessor get() = DSFieldProcessor(DoubleField) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt deleted file mode 100644 index 1da151d46..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt +++ /dev/null @@ -1,1485 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.expressions - - -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer -import kotlin.math.min - -internal fun MutableBuffer.fill(element: T, fromIndex: Int = 0, toIndex: Int = size) { - for (i in fromIndex until toIndex) this[i] = element -} - -/** - * Class holding "compiled" computation rules for derivative structures. - * - * This class implements the computation rules described in Dan Kalman's paper - * [Doubly Recursive Multivariate Automatic Differentiation](http://www1.american.edu/cas/mathstat/People/kalman/pdffiles/mmgautodiff.pdf), - * Mathematics Magazine, vol. 75, no. 3, June 2002. However, to avoid performances bottlenecks, the recursive rules are - * "compiled" once in an unfolded form. This class does this recursion unrolling and stores the computation rules as - * simple loops with pre-computed indirection arrays. - * - * This class maps all derivative computation into single dimension arrays that hold the value and partial derivatives. - * The class does not hold these arrays, which remains under the responsibility of the caller. For each combination of - * number of free parameters and derivation order, only one compiler is necessary, and this compiler will be used to - * perform computations on all arrays provided to it, which can represent hundreds or thousands of different parameters - * kept together with all their partial derivatives. - * - * The arrays on which compilers operate contain only the partial derivatives together with the 0th - * derivative, i.e., the value. The partial derivatives are stored in a compiler-specific order, which can be retrieved - * using methods [getPartialDerivativeIndex] and [getPartialDerivativeOrders]. The value is guaranteed to be stored as - * the first element (i.e., the [getPartialDerivativeIndex] method returns 0 when called with 0 for all derivation - * orders and [getPartialDerivativeOrders] returns an array filled with 0 when called with 0 as the index). - * - * Note that the ordering changes with number of parameters and derivation order. For example given 2 parameters x and - * y, df/dy is stored at index 2 when derivation order is set to 1 (in this case the array has three elements: f, - * df/dx and df/dy). If derivation order is set to 2, then df/dy will be stored at index 3 (in this case the array has - * six elements: f, df/dx, df/dxdx, df/dy, df/dxdy and df/dydy). - * - * Given this structure, users can perform some simple operations like adding, subtracting or multiplying constants and - * negating the elements by themselves, knowing if they want to mutate their array or create a new array. These simple - * operations are not provided by the compiler. The compiler provides only the more complex operations between several - * arrays. - * - * Derived from - * [Commons Math's `DSCompiler`](https://github.com/apache/commons-math/blob/924f6c357465b39beb50e3c916d5eb6662194175/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/differentiation/DSCompiler.java). - * - * @property freeParameters Number of free parameters. - * @property order Derivation order. - * @see DS - */ -public class DSCompiler> internal constructor( - public val algebra: A, - public val freeParameters: Int, - public val order: Int, - valueCompiler: DSCompiler?, - derivativeCompiler: DSCompiler?, -) { - /** - * Number of partial derivatives (including the single 0 order derivative element). - */ - public val sizes: Array by lazy { - compileSizes( - freeParameters, - order, - valueCompiler, - ) - } - - /** - * Indirection array for partial derivatives. - */ - internal val derivativesIndirection: Array by lazy { - compileDerivativesIndirection( - freeParameters, order, - valueCompiler, derivativeCompiler, - ) - } - - /** - * Indirection array of the lower derivative elements. - */ - internal val lowerIndirection: IntArray by lazy { - compileLowerIndirection( - freeParameters, order, - valueCompiler, derivativeCompiler, - ) - } - - /** - * Indirection arrays for multiplication. - */ - internal val multIndirection: Array> by lazy { - compileMultiplicationIndirection( - freeParameters, order, - valueCompiler, derivativeCompiler, lowerIndirection, - ) - } - - /** - * Indirection arrays for function composition. - */ - internal val compositionIndirection: Array> by lazy { - compileCompositionIndirection( - freeParameters, order, - valueCompiler, derivativeCompiler, - sizes, derivativesIndirection, - ) - } - - /** - * Get the array size required for holding partial derivatives' data. - * - * This number includes the single 0 order derivative element, which is - * guaranteed to be stored in the first element of the array. - */ - public val size: Int get() = sizes[freeParameters][order] - - /** - * Get the index of a partial derivative in the array. - * - * If all orders are set to 0, then the 0th order derivative is returned, which is the value of the - * function. - * - * The indices of derivatives are between 0 and [size] − 1. Their specific order is fixed for a given compiler, but - * otherwise not publicly specified. There are however some simple cases which have guaranteed indices: - * - * * the index of 0th order derivative is always 0 - * * if there is only 1 [freeParameters], then the - * derivatives are sorted in increasing derivation order (i.e., f at index 0, df/dp - * at index 1, d2f/dp2 at index 2 … - * dkf/dpk at index k), - * * if the [order] is 1, then the derivatives - * are sorted in increasing free parameter order (i.e., f at index 0, df/dx1 - * at index 1, df/dx2 at index 2 … df/dxk at index k), - * * all other cases are not publicly specified. - * - * This method is the inverse of method [getPartialDerivativeOrders]. - * - * @param orders derivation orders with respect to each parameter. - * @return index of the partial derivative. - * @see getPartialDerivativeOrders - */ - public fun getPartialDerivativeIndex(vararg orders: Int): Int { - // safety check - require(orders.size == freeParameters) { "dimension mismatch: ${orders.size} and $freeParameters" } - return getPartialDerivativeIndex(freeParameters, order, sizes, *orders) - } - - /** - * Get the derivation orders for a specific index in the array. - * - * This method is the inverse of [getPartialDerivativeIndex]. - * - * @param index of the partial derivative - * @return orders derivation orders with respect to each parameter - * @see getPartialDerivativeIndex - */ - public fun getPartialDerivativeOrders(index: Int): IntArray = derivativesIndirection[index] -} - -/** - * Compute natural logarithm of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for logarithm the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.ln( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : ExponentialOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - function[0] = ln(operand[operandOffset]) - - if (order > 0) { - val inv = one / operand[operandOffset] - var xk = inv - for (i in 1..order) { - function[i] = xk - xk *= (-i * inv) - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute integer power of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param n power to apply. - * @param result array where result must be stored (for power the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.pow( - operand: Buffer, - operandOffset: Int, - n: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : PowerOperations = algebra { - if (n == 0) { - // special case, x^0 = 1 for all x - result[resultOffset] = one - result.fill(zero, resultOffset + 1, resultOffset + size) - return - } - - // create the power function value and derivatives - // [x^n, nx^(n-1), n(n-1)x^(n-2), ... ] - val function = bufferFactory(1 + order) { zero } - - if (n > 0) { - // strictly positive power - val maxOrder: Int = min(order, n) - var xk = operand[operandOffset] pow n - maxOrder - for (i in maxOrder downTo 1) { - function[i] = xk - xk *= operand[operandOffset] - } - function[0] = xk - } else { - // strictly negative power - val inv = one / operand[operandOffset] - var xk = inv pow -n - - for (i in 0..order) { - function[i] = xk - xk *= inv - } - } - - var coefficient = number(n) - - for (i in 1..order) { - function[i] = function[i] * coefficient - coefficient *= (n - i).toDouble() - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute exponential of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for exponential the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.exp( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Ring, A : ScaleOperations, A : ExponentialOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - function.fill(exp(operand[operandOffset])) - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute square root of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for nth root the result array *cannot* be the input - * array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.sqrt( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : PowerOperations = algebra { - // create the function value and derivatives - // [x^(1/n), (1/n)x^((1/n)-1), (1-n)/n^2x^((1/n)-2), ... ] - val function = bufferFactory(1 + order) { zero } - function[0] = sqrt(operand[operandOffset]) - var xk: T = 0.5 * one / function[0] - val xReciprocal = one / operand[operandOffset] - - for (i in 1..order) { - function[i] = xk - xk *= xReciprocal * (0.5 - i) - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute cosine of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for cosine the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.cos( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Ring, A : TrigonometricOperations, A : ScaleOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - function[0] = cos(operand[operandOffset]) - - if (order > 0) { - function[1] = -sin(operand[operandOffset]) - for (i in 2..order) { - function[i] = -function[i - 2] - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute power of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param p power to apply. - * @param result array where result must be stored (for power the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.pow( - operand: Buffer, - operandOffset: Int, - p: Double, - result: MutableBuffer, - resultOffset: Int, -) where A : Ring, A : NumericAlgebra, A : PowerOperations, A : ScaleOperations = algebra { - // create the function value and derivatives - // [x^p, px^(p-1), p(p-1)x^(p-2), ... ] - val function = bufferFactory(1 + order) { zero } - var xk = operand[operandOffset] pow p - order - - for (i in order downTo 1) { - function[i] = xk - xk *= operand[operandOffset] - } - - function[0] = xk - var coefficient = p - - for (i in 1..order) { - function[i] = function[i] * coefficient - coefficient *= p - i - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute tangent of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for tangent the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.tan( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Ring, A : TrigonometricOperations, A : ScaleOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - val t = tan(operand[operandOffset]) - function[0] = t - - if (order > 0) { - - // the nth order derivative of tan has the form: - // dn(tan(x)/dxn = P_n(tan(x)) - // where P_n(t) is a degree n+1 polynomial with same parity as n+1 - // P_0(t) = t, P_1(t) = 1 + t^2, P_2(t) = 2 t (1 + t^2) ... - // the general recurrence relation for P_n is: - // P_n(x) = (1+t^2) P_(n-1)'(t) - // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array - val p = bufferFactory(order + 2) { zero } - p[1] = one - val t2 = t * t - for (n in 1..order) { - - // update and evaluate polynomial P_n(t) - var v = one - p[n + 1] = n * p[n] - var k = n + 1 - while (k >= 0) { - v = v * t2 + p[k] - if (k > 2) { - p[k - 2] = (k - 1) * p[k - 1] + (k - 3) * p[k - 3] - } else if (k == 2) { - p[0] = p[1] - } - k -= 2 - } - if (n and 0x1 == 0) { - v *= t - } - function[n] = v - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute power of a derivative structure. - * - * @param x array holding the base. - * @param xOffset offset of the base in its array. - * @param y array holding the exponent. - * @param yOffset offset of the exponent in its array. - * @param result array where result must be stored (for power the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.pow( - x: Buffer, - xOffset: Int, - y: Buffer, - yOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : ExponentialOperations = algebra { - val logX = bufferFactory(size) { zero } - ln(x, xOffset, logX, 0) - val yLogX = bufferFactory(size) { zero } - multiply(logX, 0, y, yOffset, yLogX, 0) - exp(yLogX, 0, result, resultOffset) -} - -/** - * Compute sine of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for sine the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.sin( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Ring, A : ScaleOperations, A : TrigonometricOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - function[0] = sin(operand[operandOffset]) - if (order > 0) { - function[1] = cos(operand[operandOffset]) - for (i in 2..order) { - function[i] = -function[i - 2] - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute arc cosine of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for arc cosine the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.acos( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : TrigonometricOperations, A : PowerOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - val x = operand[operandOffset] - function[0] = acos(x) - if (order > 0) { - // the nth order derivative of acos has the form: - // dn(acos(x)/dxn = P_n(x) / [1 - x^2]^((2n-1)/2) - // where P_n(x) is a degree n-1 polynomial with same parity as n-1 - // P_1(x) = -1, P_2(x) = -x, P_3(x) = -2x^2 - 1 ... - // the general recurrence relation for P_n is: - // P_n(x) = (1-x^2) P_(n-1)'(x) + (2n-3) x P_(n-1)(x) - // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array - val p = bufferFactory(order) { zero } - p[0] = -one - val x2 = x * x - val f = one / (one - x2) - var coeff = sqrt(f) - function[1] = coeff * p[0] - - for (n in 2..order) { - // update and evaluate polynomial P_n(x) - var v = zero - p[n - 1] = (n - 1) * p[n - 2] - var k = n - 1 - - while (k >= 0) { - v = v * x2 + p[k] - if (k > 2) { - p[k - 2] = (k - 1) * p[k - 1] + (2 * n - k) * p[k - 3] - } else if (k == 2) { - p[0] = p[1] - } - k -= 2 - } - - if (n and 0x1 == 0) { - v *= x - } - - coeff *= f - function[n] = coeff * v - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute arc sine of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for arc sine the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.asin( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : TrigonometricOperations, A : PowerOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - val x = operand[operandOffset] - function[0] = asin(x) - if (order > 0) { - // the nth order derivative of asin has the form: - // dn(asin(x)/dxn = P_n(x) / [1 - x^2]^((2n-1)/2) - // where P_n(x) is a degree n-1 polynomial with same parity as n-1 - // P_1(x) = 1, P_2(x) = x, P_3(x) = 2x^2 + 1 ... - // the general recurrence relation for P_n is: - // P_n(x) = (1-x^2) P_(n-1)'(x) + (2n-3) x P_(n-1)(x) - // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array - val p = bufferFactory(order) { zero } - p[0] = one - val x2 = x * x - val f = one / (one - x2) - var coeff = sqrt(f) - function[1] = coeff * p[0] - for (n in 2..order) { - - // update and evaluate polynomial P_n(x) - var v = zero - p[n - 1] = (n - 1) * p[n - 2] - var k = n - 1 - while (k >= 0) { - v = v * x2 + p[k] - if (k > 2) { - p[k - 2] = (k - 1) * p[k - 1] + (2 * n - k) * p[k - 3] - } else if (k == 2) { - p[0] = p[1] - } - k -= 2 - } - if (n and 0x1 == 0) { - v *= x - } - coeff *= f - function[n] = coeff * v - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute arc tangent of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for arc tangent the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.atan( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : TrigonometricOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - val x = operand[operandOffset] - function[0] = atan(x) - - if (order > 0) { - // the nth order derivative of atan has the form: - // dn(atan(x)/dxn = Q_n(x) / (1 + x^2)^n - // where Q_n(x) is a degree n-1 polynomial with same parity as n-1 - // Q_1(x) = 1, Q_2(x) = -2x, Q_3(x) = 6x^2 - 2 ... - // the general recurrence relation for Q_n is: - // Q_n(x) = (1+x^2) Q_(n-1)'(x) - 2(n-1) x Q_(n-1)(x) - // as per polynomial parity, we can store coefficients of both Q_(n-1) and Q_n in the same array - val q = bufferFactory(order) { zero } - q[0] = one - val x2 = x * x - val f = one / (one + x2) - var coeff = f - function[1] = coeff * q[0] - for (n in 2..order) { - - // update and evaluate polynomial Q_n(x) - var v = zero - q[n - 1] = -n * q[n - 2] - var k = n - 1 - while (k >= 0) { - v = v * x2 + q[k] - if (k > 2) { - q[k - 2] = (k - 1) * q[k - 1] + (k - 1 - 2 * n) * q[k - 3] - } else if (k == 2) { - q[0] = q[1] - } - k -= 2 - } - if (n and 0x1 == 0) { - v *= x - } - coeff *= f - function[n] = coeff * v - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute hyperbolic cosine of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for hyperbolic cosine the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.cosh( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Ring, A : ScaleOperations, A : ExponentialOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - function[0] = cosh(operand[operandOffset]) - - if (order > 0) { - function[1] = sinh(operand[operandOffset]) - for (i in 2..order) { - function[i] = function[i - 2] - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute hyperbolic tangent of a derivative structure. - * - * @param operand array holding the operand - * @param operandOffset offset of the operand in its array - * @param result array where result must be stored (for hyperbolic tangent the result array *cannot* be the input - * array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.tanh( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : ExponentialOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - val t = tanh(operand[operandOffset]) - function[0] = t - if (order > 0) { - - // the nth order derivative of tanh has the form: - // dn(tanh(x)/dxn = P_n(tanh(x)) - // where P_n(t) is a degree n+1 polynomial with same parity as n+1 - // P_0(t) = t, P_1(t) = 1 - t^2, P_2(t) = -2 t (1 - t^2) ... - // the general recurrence relation for P_n is: - // P_n(x) = (1-t^2) P_(n-1)'(t) - // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array - val p = bufferFactory(order + 2) { zero } - p[1] = one - val t2 = t * t - for (n in 1..order) { - - // update and evaluate polynomial P_n(t) - var v = zero - p[n + 1] = -n * p[n] - var k = n + 1 - while (k >= 0) { - v = v * t2 + p[k] - if (k > 2) { - p[k - 2] = (k - 1) * p[k - 1] - (k - 3) * p[k - 3] - } else if (k == 2) { - p[0] = p[1] - } - k -= 2 - } - if (n and 0x1 == 0) { - v *= t - } - function[n] = v - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute inverse hyperbolic cosine of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for inverse hyperbolic cosine the result array *cannot* be the input - * array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.acosh( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : ExponentialOperations, A : PowerOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - val x = operand[operandOffset] - function[0] = acosh(x) - - if (order > 0) { - // the nth order derivative of acosh has the form: - // dn(acosh(x)/dxn = P_n(x) / [x^2 - 1]^((2n-1)/2) - // where P_n(x) is a degree n-1 polynomial with same parity as n-1 - // P_1(x) = 1, P_2(x) = -x, P_3(x) = 2x^2 + 1 ... - // the general recurrence relation for P_n is: - // P_n(x) = (x^2-1) P_(n-1)'(x) - (2n-3) x P_(n-1)(x) - // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array - val p = bufferFactory(order) { zero } - p[0] = one - val x2 = x * x - val f = one / (x2 - one) - var coeff = sqrt(f) - function[1] = coeff * p[0] - for (n in 2..order) { - - // update and evaluate polynomial P_n(x) - var v = zero - p[n - 1] = (1 - n) * p[n - 2] - var k = n - 1 - while (k >= 0) { - v = v * x2 + p[k] - if (k > 2) { - p[k - 2] = (1 - k) * p[k - 1] + (k - 2 * n) * p[k - 3] - } else if (k == 2) { - p[0] = -p[1] - } - k -= 2 - } - if (n and 0x1 == 0) { - v *= x - } - - coeff *= f - function[n] = coeff * v - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compute composition of a derivative structure by a function. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param f array of value and derivatives of the function at the current point (i.e. at `operand[operandOffset]`). - * @param result array where result must be stored (for composition the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.compose( - operand: Buffer, - operandOffset: Int, - f: Buffer, - result: MutableBuffer, - resultOffset: Int, -) where A : Ring, A : ScaleOperations = algebra { - for (i in compositionIndirection.indices) { - val mappingI = compositionIndirection[i] - var r = zero - for (j in mappingI.indices) { - val mappingIJ = mappingI[j] - var product = mappingIJ[0] * f[mappingIJ[1]] - for (k in 2 until mappingIJ.size) { - product *= operand[operandOffset + mappingIJ[k]] - } - r += product - } - result[resultOffset + i] = r - } -} - -/** - * Compute hyperbolic sine of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for hyperbolic sine the result array *cannot* be the input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.sinh( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : ExponentialOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - function[0] = sinh(operand[operandOffset]) - - if (order > 0) { - function[1] = cosh(operand[operandOffset]) - for (i in 2..order) { - function[i] = function[i - 2] - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Perform division of two derivative structures. - * - * @param lhs array holding left-hand side of division. - * @param lhsOffset offset of the left-hand side in its array. - * @param rhs array right-hand side of division. - * @param rhsOffset offset of the right-hand side in its array. - * @param result array where result must be stored (for division the result array *cannot* be one of the input arrays). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.divide( - lhs: Buffer, - lhsOffset: Int, - rhs: Buffer, - rhsOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : PowerOperations, A : ScaleOperations = algebra { - val reciprocal = bufferFactory(size) { zero } - pow(rhs, lhsOffset, -1, reciprocal, 0) - multiply(lhs, lhsOffset, reciprocal, rhsOffset, result, resultOffset) -} - -/** - * Perform multiplication of two derivative structures. - * - * @param lhs array holding left-hand side of multiplication. - * @param lhsOffset offset of the left-hand side in its array. - * @param rhs array right-hand side of multiplication. - * @param rhsOffset offset of the right-hand side in its array. - * @param result array where result must be stored (for multiplication the result array *cannot* be one of the input - * arrays). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.multiply( - lhs: Buffer, - lhsOffset: Int, - rhs: Buffer, - rhsOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Ring, A : ScaleOperations = algebra { - for (i in multIndirection.indices) { - val mappingI = multIndirection[i] - var r = zero - - for (j in mappingI.indices) { - r += mappingI[j][0] * lhs[lhsOffset + mappingI[j][1]] * rhs[rhsOffset + mappingI[j][2]] - } - - result[resultOffset + i] = r - } -} - -/** - * Perform subtraction of two derivative structures. - * - * @param lhs array holding left-hand side of subtraction. - * @param lhsOffset offset of the left-hand side in its array. - * @param rhs array right-hand side of subtraction. - * @param rhsOffset offset of the right-hand side in its array. - * @param result array where result must be stored (it may be one of the input arrays). - * @param resultOffset offset of the result in its array. - */ -internal fun > DSCompiler.subtract( - lhs: Buffer, - lhsOffset: Int, - rhs: Buffer, - rhsOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) = algebra { - for (i in 0 until size) { - result[resultOffset + i] = lhs[lhsOffset + i] - rhs[rhsOffset + i] - } -} - -/** - * Compute inverse hyperbolic sine of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for inverse hyperbolic sine the result array *cannot* be the input - * array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.asinh( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : ExponentialOperations, A : PowerOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - val x = operand[operandOffset] - function[0] = asinh(x) - if (order > 0) { - // the nth order derivative of asinh has the form: - // dn(asinh(x)/dxn = P_n(x) / [x^2 + 1]^((2n-1)/2) - // where P_n(x) is a degree n-1 polynomial with same parity as n-1 - // P_1(x) = 1, P_2(x) = -x, P_3(x) = 2x^2 - 1 ... - // the general recurrence relation for P_n is: - // P_n(x) = (x^2+1) P_(n-1)'(x) - (2n-3) x P_(n-1)(x) - // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array - val p = bufferFactory(order) { zero } - p[0] = one - val x2 = x * x - val f = one / (one + x2) - var coeff = sqrt(f) - function[1] = coeff * p[0] - for (n in 2..order) { - - // update and evaluate polynomial P_n(x) - var v = zero - p[n - 1] = (1 - n) * p[n - 2] - var k = n - 1 - while (k >= 0) { - v = v * x2 + p[k] - if (k > 2) { - p[k - 2] = (k - 1) * p[k - 1] + (k - 2 * n) * p[k - 3] - } else if (k == 2) { - p[0] = p[1] - } - k -= 2 - } - if (n and 0x1 == 0) { - v *= x - } - coeff *= f - function[n] = coeff * v - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Perform addition of two derivative structures. - * - * @param lhs array holding left-hand side of addition. - * @param lhsOffset offset of the left-hand side in its array. - * @param rhs array right-hand side of addition. - * @param rhsOffset offset of the right-hand side in its array. - * @param result array where result must be stored (it may be one of the input arrays). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.add( - lhs: Buffer, - lhsOffset: Int, - rhs: Buffer, - rhsOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Group = algebra { - for (i in 0 until size) { - result[resultOffset + i] = lhs[lhsOffset + i] + rhs[rhsOffset + i] - } -} - -/** - * Check rules set compatibility. - * - * @param compiler other compiler to check against instance. - */ -internal fun > DSCompiler.checkCompatibility(compiler: DSCompiler) { - require(freeParameters == compiler.freeParameters) { - "dimension mismatch: $freeParameters and ${compiler.freeParameters}" - } - require(order == compiler.order) { - "dimension mismatch: $order and ${compiler.order}" - } -} - -/** - * Compute inverse hyperbolic tangent of a derivative structure. - * - * @param operand array holding the operand. - * @param operandOffset offset of the operand in its array. - * @param result array where result must be stored (for inverse hyperbolic tangent the result array *cannot* be the - * input array). - * @param resultOffset offset of the result in its array. - */ -internal fun DSCompiler.atanh( - operand: Buffer, - operandOffset: Int, - result: MutableBuffer, - resultOffset: Int, -) where A : Field, A : ExponentialOperations = algebra { - // create the function value and derivatives - val function = bufferFactory(1 + order) { zero } - val x = operand[operandOffset] - function[0] = atanh(x) - - if (order > 0) { - // the nth order derivative of atanh has the form: - // dn(atanh(x)/dxn = Q_n(x) / (1 - x^2)^n - // where Q_n(x) is a degree n-1 polynomial with same parity as n-1 - // Q_1(x) = 1, Q_2(x) = 2x, Q_3(x) = 6x^2 + 2 ... - // the general recurrence relation for Q_n is: - // Q_n(x) = (1-x^2) Q_(n-1)'(x) + 2(n-1) x Q_(n-1)(x) - // as per polynomial parity, we can store coefficients of both Q_(n-1) and Q_n in the same array - val q = bufferFactory(order) { zero } - q[0] = one - val x2 = x * x - val f = one / (one - x2) - var coeff = f - function[1] = coeff * q[0] - for (n in 2..order) { - - // update and evaluate polynomial Q_n(x) - var v = zero - q[n - 1] = n * q[n - 2] - var k = n - 1 - while (k >= 0) { - v = v * x2 + q[k] - if (k > 2) { - q[k - 2] = (k - 1) * q[k - 1] + (2 * n - k + 1) * q[k - 3] - } else if (k == 2) { - q[0] = q[1] - } - k -= 2 - } - if (n and 0x1 == 0) { - v *= x - } - coeff *= f - function[n] = coeff * v - } - } - - // apply function composition - compose(operand, operandOffset, function, result, resultOffset) -} - -/** - * Compile the sizes array. - * - * @param parameters number of free parameters. - * @param order derivation order. - * @param valueCompiler compiler for the value part. - * @return sizes array. - */ -private fun > compileSizes( - parameters: Int, order: Int, - valueCompiler: DSCompiler?, -): Array { - val sizes = Array(parameters + 1) { - IntArray(order + 1) - } - - if (parameters == 0) { - sizes[0].fill(1) - } else { - checkNotNull(valueCompiler) - valueCompiler.sizes.copyInto(sizes, endIndex = parameters) - sizes[parameters][0] = 1 - for (i in 0 until order) { - sizes[parameters][i + 1] = sizes[parameters][i] + sizes[parameters - 1][i + 1] - } - } - return sizes -} - -/** - * Compile the derivatives' indirection array. - * - * @param parameters number of free parameters. - * @param order derivation order. - * @param valueCompiler compiler for the value part. - * @param derivativeCompiler compiler for the derivative part. - * @return derivatives indirection array. - */ -private fun > compileDerivativesIndirection( - parameters: Int, - order: Int, - valueCompiler: DSCompiler?, - derivativeCompiler: DSCompiler?, -): Array { - if (parameters == 0 || order == 0) { - return Array(1) { IntArray(parameters) } - } - - val vSize: Int = valueCompiler!!.derivativesIndirection.size - val dSize: Int = derivativeCompiler!!.derivativesIndirection.size - val derivativesIndirection = Array(vSize + dSize) { IntArray(parameters) } - - // set up the indices for the value part - for (i in 0 until vSize) { - // copy the first indices, the last one remaining set to 0 - valueCompiler.derivativesIndirection[i].copyInto(derivativesIndirection[i], endIndex = parameters - 1) - } - - // set up the indices for the derivative part - for (i in 0 until dSize) { - // copy the indices - derivativeCompiler.derivativesIndirection[i].copyInto(derivativesIndirection[vSize], 0, 0, parameters) - - // increment the derivation order for the last parameter - derivativesIndirection[vSize + i][parameters - 1]++ - } - - return derivativesIndirection -} - -/** - * Compile the lower derivatives' indirection array. - * - * This indirection array contains the indices of all elements except derivatives for last derivation order. - * - * @param parameters number of free parameters. - * @param order derivation order. - * @param valueCompiler compiler for the value part. - * @param derivativeCompiler compiler for the derivative part. - * @return lower derivatives' indirection array. - */ -private fun > compileLowerIndirection( - parameters: Int, - order: Int, - valueCompiler: DSCompiler?, - derivativeCompiler: DSCompiler?, -): IntArray { - if (parameters == 0 || order <= 1) return intArrayOf(0) - checkNotNull(valueCompiler) - checkNotNull(derivativeCompiler) - - // this is an implementation of definition 6 in Dan Kalman's paper. - val vSize: Int = valueCompiler.lowerIndirection.size - val dSize: Int = derivativeCompiler.lowerIndirection.size - val lowerIndirection = IntArray(vSize + dSize) - valueCompiler.lowerIndirection.copyInto(lowerIndirection, endIndex = vSize) - for (i in 0 until dSize) { - lowerIndirection[vSize + i] = valueCompiler.size + derivativeCompiler.lowerIndirection[i] - } - return lowerIndirection -} - -/** - * Compile the multiplication indirection array. - * - * This indirection array contains the indices of all pairs of elements involved when computing a multiplication. This - * allows a straightforward loop-based multiplication (see [multiply]). - * - * @param parameters number of free parameters. - * @param order derivation order. - * @param valueCompiler compiler for the value part. - * @param derivativeCompiler compiler for the derivative part. - * @param lowerIndirection lower derivatives' indirection array. - * @return multiplication indirection array. - */ -@Suppress("UNCHECKED_CAST") -private fun > compileMultiplicationIndirection( - parameters: Int, - order: Int, - valueCompiler: DSCompiler?, - derivativeCompiler: DSCompiler?, - lowerIndirection: IntArray, -): Array> { - if (parameters == 0 || order == 0) return arrayOf(arrayOf(intArrayOf(1, 0, 0))) - - // this is an implementation of definition 3 in Dan Kalman's paper. - val vSize = valueCompiler!!.multIndirection.size - val dSize = derivativeCompiler!!.multIndirection.size - val multIndirection: Array?> = arrayOfNulls(vSize + dSize) - valueCompiler.multIndirection.copyInto(multIndirection, endIndex = vSize) - - for (i in 0 until dSize) { - val dRow = derivativeCompiler.multIndirection[i] - val row: List = buildList(dRow.size * 2) { - for (j in dRow.indices) { - add(intArrayOf(dRow[j][0], lowerIndirection[dRow[j][1]], vSize + dRow[j][2])) - add(intArrayOf(dRow[j][0], vSize + dRow[j][1], lowerIndirection[dRow[j][2]])) - } - } - - // combine terms with similar derivation orders - val combined: List = buildList(row.size) { - for (j in row.indices) { - val termJ = row[j] - if (termJ[0] > 0) { - for (k in j + 1 until row.size) { - val termK = row[k] - - if (termJ[1] == termK[1] && termJ[2] == termK[2]) { - // combine termJ and termK - termJ[0] += termK[0] - // make sure we will skip termK later on in the outer loop - termK[0] = 0 - } - } - - add(termJ) - } - } - } - - multIndirection[vSize + i] = combined.toTypedArray() - } - - return multIndirection as Array> -} - -/** - * Compile the indirection array of function composition. - * - * This indirection array contains the indices of all sets of elements involved when computing a composition. This - * allows a straightforward loop-based composition (see [compose]). - * - * @param parameters number of free parameters. - * @param order derivation order. - * @param valueCompiler compiler for the value part. - * @param derivativeCompiler compiler for the derivative part. - * @param sizes sizes array. - * @param derivativesIndirection derivatives indirection array. - * @return multiplication indirection array. - */ -@Suppress("UNCHECKED_CAST") -private fun > compileCompositionIndirection( - parameters: Int, - order: Int, - valueCompiler: DSCompiler?, - derivativeCompiler: DSCompiler?, - sizes: Array, - derivativesIndirection: Array, -): Array> { - if (parameters == 0 || order == 0) { - return arrayOf(arrayOf(intArrayOf(1, 0))) - } - - val vSize = valueCompiler!!.compositionIndirection.size - val dSize = derivativeCompiler!!.compositionIndirection.size - val compIndirection: Array?> = arrayOfNulls(vSize + dSize) - - // the composition rules from the value part can be reused as is - valueCompiler.compositionIndirection.copyInto(compIndirection, endIndex = vSize) - - // the composition rules for the derivative part are deduced by differentiation the rules from the - // underlying compiler once with respect to the parameter this compiler handles and the underlying one - // did not handle - - // the composition rules for the derivative part are deduced by differentiation the rules from the - // underlying compiler once with respect to the parameter this compiler handles and the underlying one did - // not handle - for (i in 0 until dSize) { - val row: List = buildList { - for (term in derivativeCompiler.compositionIndirection[i]) { - - // handle term p * f_k(g(x)) * g_l1(x) * g_l2(x) * ... * g_lp(x) - - // derive the first factor in the term: f_k with respect to new parameter - val derivedTermF = IntArray(term.size + 1) - derivedTermF[0] = term[0] // p - derivedTermF[1] = term[1] + 1 // f_(k+1) - val orders = IntArray(parameters) - orders[parameters - 1] = 1 - derivedTermF[term.size] = getPartialDerivativeIndex( - parameters, - order, - sizes, - *orders - ) // g_1 - - for (j in 2 until term.size) { - // convert the indices as the mapping for the current order is different from the mapping with one - // less order - derivedTermF[j] = convertIndex( - term[j], parameters, - derivativeCompiler.derivativesIndirection, - parameters, order, sizes - ) - } - - derivedTermF.sort(2, derivedTermF.size) - add(derivedTermF) - - // derive the various g_l - for (l in 2 until term.size) { - val derivedTermG = IntArray(term.size) - derivedTermG[0] = term[0] - derivedTermG[1] = term[1] - - for (j in 2 until term.size) { - // convert the indices as the mapping for the current order - // is different from the mapping with one less order - derivedTermG[j] = convertIndex( - term[j], - parameters, - derivativeCompiler.derivativesIndirection, - parameters, - order, - sizes, - ) - - if (j == l) { - // derive this term - derivativesIndirection[derivedTermG[j]].copyInto(orders, endIndex = parameters) - orders[parameters - 1]++ - - derivedTermG[j] = getPartialDerivativeIndex( - parameters, - order, - sizes, - *orders, - ) - } - } - - derivedTermG.sort(2, derivedTermG.size) - add(derivedTermG) - } - } - } - - // combine terms with similar derivation orders - val combined: List = buildList(row.size) { - for (j in row.indices) { - val termJ = row[j] - - if (termJ[0] > 0) { - (j + 1 until row.size).map { k -> row[k] }.forEach { termK -> - var equals = termJ.size == termK.size - var l = 1 - - while (equals && l < termJ.size) { - equals = equals and (termJ[l] == termK[l]) - ++l - } - - if (equals) { - // combine termJ and termK - termJ[0] += termK[0] - // make sure we will skip termK later on in the outer loop - termK[0] = 0 - } - } - - add(termJ) - } - } - } - - compIndirection[vSize + i] = combined.toTypedArray() - } - - return compIndirection as Array> -} - -/** - * Get the index of a partial derivative in an array. - * - * @param parameters number of free parameters. - * @param order derivation order. - * @param sizes sizes array. - * @param orders derivation orders with respect to each parameter (the length of this array must match the number of - * parameters). - * @return index of the partial derivative. - */ -private fun getPartialDerivativeIndex( - parameters: Int, - order: Int, - sizes: Array, - vararg orders: Int, -): Int { - - // the value is obtained by diving into the recursive Dan Kalman's structure - // this is theorem 2 of his paper, with recursion replaced by iteration - var index = 0 - var m = order - var ordersSum = 0 - - for (i in parameters - 1 downTo 0) { - // derivative order for current free parameter - var derivativeOrder = orders[i] - - // safety check - ordersSum += derivativeOrder - require(ordersSum <= order) { "number is too large: $ordersSum > $order" } - - while (derivativeOrder-- > 0) { - // as long as we differentiate according to current free parameter, - // we have to skip the value part and dive into the derivative part, - // so we add the size of the value part to the base index - index += sizes[i][m--] - } - } - - return index -} - -/** - * Convert an index from one (parameters, order) structure to another. - * - * @param index index of a partial derivative in source derivative structure. - * @param srcP number of free parameters in source derivative structure. - * @param srcDerivativesIndirection derivatives indirection array for the source derivative structure. - * @param destP number of free parameters in destination derivative structure. - * @param destO derivation order in destination derivative structure. - * @param destSizes sizes array for the destination derivative structure. - * @return index of the partial derivative with the *same* characteristics in destination derivative structure. - */ -private fun convertIndex( - index: Int, - srcP: Int, - srcDerivativesIndirection: Array, - destP: Int, - destO: Int, - destSizes: Array, -): Int { - val orders = IntArray(destP) - srcDerivativesIndirection[index].copyInto(orders, endIndex = min(srcP, destP)) - return getPartialDerivativeIndex(destP, destO, destSizes, *orders) -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt index 7c8a957c7..dbc1431b3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt @@ -1,64 +1,48 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.expressions -import space.kscience.kmath.operations.Algebra +import space.kscience.kmath.misc.StringSymbol +import space.kscience.kmath.misc.Symbol /** - * Represents expression, which structure can be differentiated. + * Represents expression which structure can be differentiated. * * @param T the type this expression takes as argument and returns. + * @param R the type of expression this expression can be differentiated to. */ -public interface DifferentiableExpression : Expression { +public interface DifferentiableExpression> : Expression { /** * Differentiates this expression by ordered collection of [symbols]. * * @param symbols the symbols. * @return the derivative or `null`. */ - public fun derivativeOrNull(symbols: List): Expression? + public fun derivativeOrNull(symbols: List): R? } -public fun DifferentiableExpression.derivative(symbols: List): Expression = +public fun > DifferentiableExpression.derivative(symbols: List): R = derivativeOrNull(symbols) ?: error("Derivative by symbols $symbols not provided") -public fun DifferentiableExpression.derivative(vararg symbols: Symbol): Expression = +public fun > DifferentiableExpression.derivative(vararg symbols: Symbol): R = derivative(symbols.toList()) -public fun DifferentiableExpression.derivative(name: String): Expression = - derivative(StringSymbol(name)) - -/** - * A special type of [DifferentiableExpression] which returns typed expressions as derivatives. - * - * @param R the type of expression this expression can be differentiated to. - */ -public interface SpecialDifferentiableExpression> : DifferentiableExpression { - override fun derivativeOrNull(symbols: List): R? -} - -public fun > SpecialDifferentiableExpression.derivative(symbols: List): R = - derivativeOrNull(symbols) ?: error("Derivative by symbols $symbols not provided") - -public fun > SpecialDifferentiableExpression.derivative(vararg symbols: Symbol): R = - derivative(symbols.toList()) - -public fun > SpecialDifferentiableExpression.derivative(name: String): R = +public fun > DifferentiableExpression.derivative(name: String): R = derivative(StringSymbol(name)) /** * A [DifferentiableExpression] that defines only first derivatives */ -public abstract class FirstDerivativeExpression : DifferentiableExpression { +public abstract class FirstDerivativeExpression> : DifferentiableExpression { /** * Returns first derivative of this expression by given [symbol]. */ - public abstract fun derivativeOrNull(symbol: Symbol): Expression? + public abstract fun derivativeOrNull(symbol: Symbol): R? - public final override fun derivativeOrNull(symbols: List): Expression? { + public final override fun derivativeOrNull(symbols: List): R? { val dSymbol = symbols.firstOrNull() ?: return null return derivativeOrNull(dSymbol) } @@ -66,10 +50,7 @@ public abstract class FirstDerivativeExpression : DifferentiableExpression /** * A factory that converts an expression in autodiff variables to a [DifferentiableExpression] - * @param T type of the constants for the expression - * @param I type of the actual expression state - * @param A type of expression algebra */ -public fun interface AutoDiffProcessor> { - public fun differentiate(function: A.() -> I): DifferentiableExpression +public fun interface AutoDiffProcessor, out R : Expression> { + public fun process(function: A.() -> I): DifferentiableExpression } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt index f350303bc..a9ab8648f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt @@ -1,11 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.expressions -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.StringSymbol +import space.kscience.kmath.misc.Symbol import space.kscience.kmath.operations.Algebra import kotlin.jvm.JvmName import kotlin.properties.ReadOnlyProperty @@ -25,99 +26,12 @@ public fun interface Expression { public operator fun invoke(arguments: Map): T } -/** - * Specialization of [Expression] for [Double] allowing better performance because of using array. - */ -@UnstableKMathAPI -public interface DoubleExpression : Expression { - /** - * The indexer of this expression's arguments that should be used to build array for [invoke]. - * - * Implementations must fulfil the following requirement: for any argument symbol `x` and its value `y`, - * `indexer.indexOf(x) == arguments.indexOf(y)` if `arguments` is the array passed to [invoke]. - */ - public val indexer: SymbolIndexer - - public override operator fun invoke(arguments: Map): Double = - this(DoubleArray(indexer.symbols.size) { arguments.getValue(indexer.symbols[it]) }) - - /** - * Calls this expression from arguments. - * - * @param arguments the array of arguments. - * @return the value. - */ - public operator fun invoke(arguments: DoubleArray): Double - - public companion object{ - internal val EMPTY_DOUBLE_ARRAY = DoubleArray(0) - } -} - -/** - * Specialization of [Expression] for [Int] allowing better performance because of using array. - */ -@UnstableKMathAPI -public interface IntExpression : Expression { - /** - * The indexer of this expression's arguments that should be used to build array for [invoke]. - * - * Implementations must fulfil the following requirement: for any argument symbol `x` and its value `y`, - * `indexer.indexOf(x) == arguments.indexOf(y)` if `arguments` is the array passed to [invoke]. - */ - public val indexer: SymbolIndexer - - public override operator fun invoke(arguments: Map): Int = - this(IntArray(indexer.symbols.size) { arguments.getValue(indexer.symbols[it]) }) - - /** - * Calls this expression from arguments. - * - * @param arguments the array of arguments. - * @return the value. - */ - public operator fun invoke(arguments: IntArray): Int - - public companion object{ - internal val EMPTY_INT_ARRAY = IntArray(0) - } -} - -/** - * Specialization of [Expression] for [Long] allowing better performance because of using array. - */ -@UnstableKMathAPI -public interface LongExpression : Expression { - /** - * The indexer of this expression's arguments that should be used to build array for [invoke]. - * - * Implementations must fulfil the following requirement: for any argument symbol `x` and its value `y`, - * `indexer.indexOf(x) == arguments.indexOf(y)` if `arguments` is the array passed to [invoke]. - */ - public val indexer: SymbolIndexer - - public override operator fun invoke(arguments: Map): Long = - this(LongArray(indexer.symbols.size) { arguments.getValue(indexer.symbols[it]) }) - - /** - * Calls this expression from arguments. - * - * @param arguments the array of arguments. - * @return the value. - */ - public operator fun invoke(arguments: LongArray): Long - - public companion object{ - internal val EMPTY_LONG_ARRAY = LongArray(0) - } -} - /** * Calls this expression without providing any arguments. * * @return a value. */ -public operator fun Expression.invoke(): T = this(emptyMap()) +public operator fun Expression.invoke(): T = invoke(emptyMap()) /** * Calls this expression from arguments. @@ -126,89 +40,18 @@ public operator fun Expression.invoke(): T = this(emptyMap()) * @return a value. */ @JvmName("callBySymbol") -public operator fun Expression.invoke(vararg pairs: Pair): T = this( - when (pairs.size) { - 0 -> emptyMap() - 1 -> mapOf(pairs[0]) - else -> hashMapOf(*pairs) - } -) +public operator fun Expression.invoke(vararg pairs: Pair): T = invoke(mapOf(*pairs)) /** * Calls this expression from arguments. * - * @param pairs the pairs of arguments' names to value. + * @param pairs the pairs of arguments' names to values. * @return a value. */ @JvmName("callByString") -public operator fun Expression.invoke(vararg pairs: Pair): T = this( - when (pairs.size) { - 0 -> emptyMap() +public operator fun Expression.invoke(vararg pairs: Pair): T = + invoke(mapOf(*pairs).mapKeys { StringSymbol(it.key) }) - 1 -> { - val (k, v) = pairs[0] - mapOf(StringSymbol(k) to v) - } - - else -> hashMapOf(*Array>(pairs.size) { - val (k, v) = pairs[it] - StringSymbol(k) to v - }) - } -) - - - -/** - * Calls this expression without providing any arguments. - * - * @return a value. - */ -@UnstableKMathAPI -public operator fun DoubleExpression.invoke(): Double = this(DoubleExpression.EMPTY_DOUBLE_ARRAY) - -/** - * Calls this expression from arguments. - * - * @param pairs the pairs of arguments to values. - * @return a value. - */ -@UnstableKMathAPI -public operator fun DoubleExpression.invoke(vararg arguments: Double): Double = this(arguments) - -/** - * Calls this expression without providing any arguments. - * - * @return a value. - */ -@UnstableKMathAPI -public operator fun IntExpression.invoke(): Int = this(IntExpression.EMPTY_INT_ARRAY) - -/** - * Calls this expression from arguments. - * - * @param pairs the pairs of arguments to values. - * @return a value. - */ -@UnstableKMathAPI -public operator fun IntExpression.invoke(vararg arguments: Int): Int = this(arguments) - -/** - * Calls this expression without providing any arguments. - * - * @return a value. - */ -@UnstableKMathAPI -public operator fun LongExpression.invoke(): Long = this(LongExpression.EMPTY_LONG_ARRAY) - -/** - * Calls this expression from arguments. - * - * @param pairs the pairs of arguments to values. - * @return a value. - */ -@UnstableKMathAPI -public operator fun LongExpression.invoke(vararg arguments: Long): Long = this(arguments) /** * A context for expression construction @@ -219,7 +62,7 @@ public operator fun LongExpression.invoke(vararg arguments: Long): Long = this(a public interface ExpressionAlgebra : Algebra { /** - * A constant expression that does not depend on arguments. + * A constant expression which does not depend on arguments */ public fun const(value: T): E } @@ -227,7 +70,6 @@ public interface ExpressionAlgebra : Algebra { /** * Bind a symbol by name inside the [ExpressionAlgebra] */ -public val ExpressionAlgebra.binding: ReadOnlyProperty - get() = ReadOnlyProperty { _, property -> - bindSymbol(property.name) ?: error("A variable with name ${property.name} does not exist") - } +public fun ExpressionAlgebra.binding(): ReadOnlyProperty = ReadOnlyProperty { _, property -> + bindSymbol(property.name) ?: error("A variable with name ${property.name} does not exist") +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt deleted file mode 100644 index c802fe04c..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.expressions - -public class ExpressionWithDefault( - private val origin: Expression, - private val defaultArgs: Map, -) : Expression { - override fun invoke(arguments: Map): T = origin.invoke(defaultArgs + arguments) -} - -public fun Expression.withDefaultArgs(defaultArgs: Map): ExpressionWithDefault = - ExpressionWithDefault(this, defaultArgs) - - -public class DiffExpressionWithDefault( - private val origin: DifferentiableExpression, - private val defaultArgs: Map, -) : DifferentiableExpression { - - override fun invoke(arguments: Map): T = origin.invoke(defaultArgs + arguments) - - override fun derivativeOrNull(symbols: List): Expression? = - origin.derivativeOrNull(symbols)?.withDefaultArgs(defaultArgs) -} - -public fun DifferentiableExpression.withDefaultArgs(defaultArgs: Map): DiffExpressionWithDefault = - DiffExpressionWithDefault(this, defaultArgs) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 1054d1aa1..994d52a73 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -1,69 +1,74 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.expressions +import space.kscience.kmath.misc.StringSymbol import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract /** * A context class for [Expression] construction. * * @param algebra The algebra to provide for Expressions built. */ -public abstract class FunctionalExpressionAlgebra>( +public abstract class FunctionalExpressionAlgebra>( public val algebra: A, ) : ExpressionAlgebra> { /** - * Builds an Expression of constant expression that does not depend on arguments. + * Builds an Expression of constant expression which does not depend on arguments. */ - override fun const(value: T): Expression = Expression { value } + public override fun const(value: T): Expression = Expression { value } /** * Builds an Expression to access a variable. */ - override fun bindSymbolOrNull(value: String): Expression? = Expression { arguments -> + public override fun bindSymbolOrNull(value: String): Expression? = Expression { arguments -> algebra.bindSymbolOrNull(value) ?: arguments[StringSymbol(value)] ?: error("Symbol '$value' is not supported in $this") } - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + /** + * Builds an Expression of dynamic call of binary operation [operation] on [left] and [right]. + */ + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = { left, right -> Expression { arguments -> - algebra.binaryOperationFunction(operation)(left(arguments), right(arguments)) + algebra.binaryOperationFunction(operation)(left.invoke(arguments), right.invoke(arguments)) } } - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> - Expression { arguments -> algebra.unaryOperation(operation, arg(arguments)) } + /** + * Builds an Expression of dynamic call of unary operation with name [operation] on [arg]. + */ + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> + Expression { arguments -> algebra.unaryOperationFunction(operation)(arg.invoke(arguments)) } } } /** * A context class for [Expression] construction for [Ring] algebras. */ -public open class FunctionalExpressionGroup>( +public open class FunctionalExpressionGroup>( algebra: A, ) : FunctionalExpressionAlgebra(algebra), Group> { - override val zero: Expression get() = const(algebra.zero) + public override val zero: Expression get() = const(algebra.zero) - override fun Expression.unaryMinus(): Expression = - unaryOperation(GroupOps.MINUS_OPERATION, this) + public override fun Expression.unaryMinus(): Expression = + unaryOperation(GroupOperations.MINUS_OPERATION, this) /** * Builds an Expression of addition of two another expressions. */ - override fun add(left: Expression, right: Expression): Expression = - binaryOperation(GroupOps.PLUS_OPERATION, left, right) + public override fun add(a: Expression, b: Expression): Expression = + binaryOperation(GroupOperations.PLUS_OPERATION, a, b) // /** // * Builds an Expression of multiplication of expression by number. // */ -// override fun multiply(a: Expression, k: Number): Expression = Expression { arguments -> +// public override fun multiply(a: Expression, k: Number): Expression = Expression { arguments -> // algebra.multiply(a.invoke(arguments), k) // } @@ -72,125 +77,111 @@ public open class FunctionalExpressionGroup>( public operator fun T.plus(arg: Expression): Expression = arg + this public operator fun T.minus(arg: Expression): Expression = arg - this - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) } -public open class FunctionalExpressionRing>( +public open class FunctionalExpressionRing>( algebra: A, ) : FunctionalExpressionGroup(algebra), Ring> { - override val one: Expression get() = const(algebra.one) + public override val one: Expression get() = const(algebra.one) /** * Builds an Expression of multiplication of two expressions. */ - override fun multiply(left: Expression, right: Expression): Expression = - binaryOperationFunction(RingOps.TIMES_OPERATION)(left, right) + public override fun multiply(a: Expression, b: Expression): Expression = + binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) public operator fun Expression.times(arg: T): Expression = this * const(arg) public operator fun T.times(arg: Expression): Expression = arg * this - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) } -public open class FunctionalExpressionField>( +public open class FunctionalExpressionField>( algebra: A, ) : FunctionalExpressionRing(algebra), Field>, ScaleOperations> { /** * Builds an Expression of division an expression by another one. */ - override fun divide(left: Expression, right: Expression): Expression = - binaryOperationFunction(FieldOps.DIV_OPERATION)(left, right) + public override fun divide(a: Expression, b: Expression): Expression = + binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) public operator fun Expression.div(arg: T): Expression = this / const(arg) public operator fun T.div(arg: Expression): Expression = arg / this - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) - override fun scale(a: Expression, value: Double): Expression = algebra { + public override fun scale(a: Expression, value: Double): Expression = algebra { Expression { args -> a(args) * value } } - override fun bindSymbolOrNull(value: String): Expression? = + public override fun bindSymbolOrNull(value: String): Expression? = super.bindSymbolOrNull(value) } -public open class FunctionalExpressionExtendedField>( +public open class FunctionalExpressionExtendedField>( algebra: A, ) : FunctionalExpressionField(algebra), ExtendedField> { - override fun number(value: Number): Expression = const(algebra.number(value)) + public override fun number(value: Number): Expression = const(algebra.number(value)) - override fun sqrt(arg: Expression): Expression = + public override fun sqrt(arg: Expression): Expression = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) - override fun sin(arg: Expression): Expression = + public override fun sin(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) - override fun cos(arg: Expression): Expression = + public override fun cos(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) - override fun asin(arg: Expression): Expression = + public override fun asin(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) - override fun acos(arg: Expression): Expression = + public override fun acos(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) - override fun atan(arg: Expression): Expression = + public override fun atan(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) - override fun power(arg: Expression, pow: Number): Expression = + public override fun power(arg: Expression, pow: Number): Expression = binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) - override fun exp(arg: Expression): Expression = + public override fun exp(arg: Expression): Expression = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - override fun ln(arg: Expression): Expression = + public override fun ln(arg: Expression): Expression = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) + + public override fun bindSymbol(value: String): Expression = super.bindSymbol(value) } -public inline fun > A.expressionInGroup( - block: FunctionalExpressionGroup.() -> Expression, -): Expression { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return FunctionalExpressionGroup(this).block() -} +public inline fun > A.expressionInSpace(block: FunctionalExpressionGroup.() -> Expression): Expression = + FunctionalExpressionGroup(this).block() -public inline fun > A.expressionInRing( - block: FunctionalExpressionRing.() -> Expression, -): Expression { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return FunctionalExpressionRing(this).block() -} +public inline fun > A.expressionInRing(block: FunctionalExpressionRing.() -> Expression): Expression = + FunctionalExpressionRing(this).block() -public inline fun > A.expressionInField( - block: FunctionalExpressionField.() -> Expression, -): Expression { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return FunctionalExpressionField(this).block() -} +public inline fun > A.expressionInField(block: FunctionalExpressionField.() -> Expression): Expression = + FunctionalExpressionField(this).block() public inline fun > A.expressionInExtendedField( block: FunctionalExpressionExtendedField.() -> Expression, ): Expression = FunctionalExpressionExtendedField(this).block() - -public inline fun DoubleField.expression( - block: FunctionalExpressionExtendedField.() -> Expression, -): Expression = FunctionalExpressionExtendedField(this).block() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt index 9705a3f03..67881d9af 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt @@ -1,92 +1,115 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.expressions +import space.kscience.kmath.misc.StringSymbol +import space.kscience.kmath.misc.Symbol import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbolOrNull /** * A Mathematical Syntax Tree (MST) node for mathematical expressions. * * @author Alexander Nozik */ -public sealed interface MST { +public sealed class MST { + /** + * A node containing raw string. + * + * @property value the value of this node. + */ + public data class Symbolic(val value: String) : MST() /** * A node containing a numeric value or scalar. * * @property value the value of this number. */ - public data class Numeric(val value: Number) : MST + public data class Numeric(val value: Number) : MST() /** - * A node containing a unary operation. + * A node containing an unary operation. * * @property operation the identifier of operation. * @property value the argument of this operation. */ - public data class Unary(val operation: String, val value: MST) : MST + public data class Unary(val operation: String, val value: MST) : MST() /** * A node containing binary operation. * - * @property operation the identifier of operation. + * @property operation the identifier operation. * @property left the left operand. * @property right the right operand. */ - public data class Binary(val operation: String, val left: MST, val right: MST) : MST + public data class Binary(val operation: String, val left: MST, val right: MST) : MST() } // TODO add a function with named arguments +/** + * Interprets the [MST] node with this [Algebra]. + * + * @receiver the algebra that provides operations. + * @param node the node to evaluate. + * @return the value of expression. + * @author Alexander Nozik + */ +public fun Algebra.evaluate(node: MST): T = when (node) { + is MST.Numeric -> (this as? NumericAlgebra)?.number(node.value) + ?: error("Numeric nodes are not supported by $this") + + is MST.Symbolic -> bindSymbol(node.value) + + is MST.Unary -> when { + this is NumericAlgebra && node.value is MST.Numeric -> unaryOperationFunction(node.operation)(number(node.value.value)) + else -> unaryOperationFunction(node.operation)(evaluate(node.value)) + } + + is MST.Binary -> when { + this is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> + binaryOperationFunction(node.operation)(number(node.left.value), number(node.right.value)) + + this is NumericAlgebra && node.left is MST.Numeric -> + leftSideNumberOperationFunction(node.operation)(node.left.value, evaluate(node.right)) + + this is NumericAlgebra && node.right is MST.Numeric -> + rightSideNumberOperationFunction(node.operation)(evaluate(node.left), node.right.value) + + else -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right)) + } +} + +internal class InnerAlgebra(val algebra: Algebra, val arguments: Map) : NumericAlgebra { + override fun bindSymbolOrNull(value: String): T? = algebra.bindSymbolOrNull(value) ?: arguments[StringSymbol(value)] + + override fun unaryOperation(operation: String, arg: T): T = + algebra.unaryOperation(operation, arg) + + override fun binaryOperation(operation: String, left: T, right: T): T = + algebra.binaryOperation(operation, left, right) + + override fun unaryOperationFunction(operation: String): (arg: T) -> T = + algebra.unaryOperationFunction(operation) + + override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = + algebra.binaryOperationFunction(operation) + + @Suppress("UNCHECKED_CAST") + override fun number(value: Number): T = if (algebra is NumericAlgebra<*>) + (algebra as NumericAlgebra).number(value) + else + error("Numeric nodes are not supported by $this") +} /** * Interprets the [MST] node with this [Algebra] and optional [arguments] */ -public fun MST.interpret(algebra: Algebra, arguments: Map): T = when (this) { - is MST.Numeric -> (algebra as NumericAlgebra?)?.number(value) - ?: error("Numeric nodes are not supported by $algebra") - - is Symbol -> algebra.bindSymbolOrNull(this) ?: arguments.getValue(this) - - is MST.Unary -> when { - algebra is NumericAlgebra && this.value is MST.Numeric -> algebra.unaryOperation( - this.operation, - algebra.number(this.value.value), - ) - else -> algebra.unaryOperationFunction(this.operation)(this.value.interpret(algebra, arguments)) - } - - is MST.Binary -> when { - algebra is NumericAlgebra && this.left is MST.Numeric && this.right is MST.Numeric -> algebra.binaryOperation( - this.operation, - algebra.number(this.left.value), - algebra.number(this.right.value), - ) - - algebra is NumericAlgebra && this.left is MST.Numeric -> algebra.leftSideNumberOperation( - this.operation, - this.left.value, - this.right.interpret(algebra, arguments), - ) - - algebra is NumericAlgebra && this.right is MST.Numeric -> algebra.rightSideNumberOperation( - this.operation, - left.interpret(algebra, arguments), - right.value, - ) - - else -> algebra.binaryOperation( - this.operation, - this.left.interpret(algebra, arguments), - this.right.interpret(algebra, arguments), - ) - } -} +public fun MST.interpret(algebra: Algebra, arguments: Map): T = + InnerAlgebra(algebra, arguments).evaluate(this) /** * Interprets the [MST] node with this [Algebra] and optional [arguments] @@ -95,17 +118,12 @@ public fun MST.interpret(algebra: Algebra, arguments: Map): T * @param algebra the algebra that provides operations. * @return the value of expression. */ -public fun MST.interpret(algebra: Algebra, vararg arguments: Pair): T = interpret( - algebra, - when (arguments.size) { - 0 -> emptyMap() - 1 -> mapOf(arguments[0]) - else -> hashMapOf(*arguments) - }, -) +public fun MST.interpret(algebra: Algebra, vararg arguments: Pair): T = + interpret(algebra, mapOf(*arguments)) /** * Interpret this [MST] as expression. */ -public fun MST.toExpression(algebra: Algebra): Expression = - Expression { arguments -> interpret(algebra, arguments) } +public fun MST.toExpression(algebra: Algebra): Expression = Expression { arguments -> + interpret(algebra, arguments) +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt index c894cf00a..32a7efc1e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt @@ -1,25 +1,25 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.expressions -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* /** * [Algebra] over [MST] nodes. */ -public object MstNumericAlgebra : NumericAlgebra { - override fun number(value: Number): MST.Numeric = MST.Numeric(value) - override fun bindSymbolOrNull(value: String): Symbol = StringSymbol(value) - override fun bindSymbol(value: String): Symbol = bindSymbolOrNull(value) +public object MstAlgebra : NumericAlgebra { + public override fun number(value: Number): MST.Numeric = MST.Numeric(value) + public override fun bindSymbolOrNull(value: String): MST.Symbolic = MST.Symbolic(value) + override fun bindSymbol(value: String): MST.Symbolic = bindSymbolOrNull(value) - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = { arg -> MST.Unary(operation, arg) } - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = { left, right -> MST.Binary(operation, left, right) } } @@ -27,28 +27,28 @@ public object MstNumericAlgebra : NumericAlgebra { * [Group] over [MST] nodes. */ public object MstGroup : Group, NumericAlgebra, ScaleOperations { - override val zero: MST.Numeric = number(0.0) + public override val zero: MST.Numeric = number(0.0) - override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value) - override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun add(left: MST, right: MST): MST.Binary = binaryOperationFunction(GroupOps.PLUS_OPERATION)(left, right) - override operator fun MST.unaryPlus(): MST.Unary = - unaryOperationFunction(GroupOps.PLUS_OPERATION)(this) + public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value) + public override fun bindSymbolOrNull(value: String): MST.Symbolic = MstAlgebra.bindSymbolOrNull(value) + public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOperations.PLUS_OPERATION)(a, b) + public override operator fun MST.unaryPlus(): MST.Unary = + unaryOperationFunction(GroupOperations.PLUS_OPERATION)(this) - override operator fun MST.unaryMinus(): MST.Unary = - unaryOperationFunction(GroupOps.MINUS_OPERATION)(this) + public override operator fun MST.unaryMinus(): MST.Unary = + unaryOperationFunction(GroupOperations.MINUS_OPERATION)(this) - override operator fun MST.minus(arg: MST): MST.Binary = - binaryOperationFunction(GroupOps.MINUS_OPERATION)(this, arg) + public override operator fun MST.minus(b: MST): MST.Binary = + binaryOperationFunction(GroupOperations.MINUS_OPERATION)(this, b) - override fun scale(a: MST, value: Double): MST.Binary = - binaryOperationFunction(RingOps.TIMES_OPERATION)(a, number(value)) + public override fun scale(a: MST, value: Double): MST.Binary = + binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(value)) - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = - MstNumericAlgebra.binaryOperationFunction(operation) + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + MstAlgebra.binaryOperationFunction(operation) - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = - MstNumericAlgebra.unaryOperationFunction(operation) + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + MstAlgebra.unaryOperationFunction(operation) } /** @@ -56,29 +56,29 @@ public object MstGroup : Group, NumericAlgebra, ScaleOperations { */ @Suppress("OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -public object MstRing : Ring, NumbersAddOps, ScaleOperations { - override inline val zero: MST.Numeric get() = MstGroup.zero - override val one: MST.Numeric = number(1.0) +public object MstRing : Ring, NumbersAddOperations, ScaleOperations { + public override inline val zero: MST.Numeric get() = MstGroup.zero + public override val one: MST.Numeric = number(1.0) - override fun number(value: Number): MST.Numeric = MstGroup.number(value) - override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun add(left: MST, right: MST): MST.Binary = MstGroup.add(left, right) + public override fun number(value: Number): MST.Numeric = MstGroup.number(value) + public override fun bindSymbolOrNull(value: String): MST.Symbolic = MstAlgebra.bindSymbolOrNull(value) + public override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b) - override fun scale(a: MST, value: Double): MST.Binary = - MstGroup.binaryOperationFunction(RingOps.TIMES_OPERATION)(a, MstGroup.number(value)) + public override fun scale(a: MST, value: Double): MST.Binary = + MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - override fun multiply(left: MST, right: MST): MST.Binary = - binaryOperationFunction(RingOps.TIMES_OPERATION)(left, right) + public override fun multiply(a: MST, b: MST): MST.Binary = + binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) - override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus } - override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus } - override operator fun MST.minus(arg: MST): MST.Binary = MstGroup { this@minus - arg } + public override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus } + public override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus } + public override operator fun MST.minus(b: MST): MST.Binary = MstGroup { this@minus - b } - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstGroup.binaryOperationFunction(operation) - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = - MstNumericAlgebra.unaryOperationFunction(operation) + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + MstAlgebra.unaryOperationFunction(operation) } /** @@ -86,29 +86,29 @@ public object MstRing : Ring, NumbersAddOps, ScaleOperations { */ @Suppress("OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -public object MstField : Field, NumbersAddOps, ScaleOperations { - override inline val zero: MST.Numeric get() = MstRing.zero - override inline val one: MST.Numeric get() = MstRing.one +public object MstField : Field, NumbersAddOperations, ScaleOperations { + public override inline val zero: MST.Numeric get() = MstRing.zero + public override inline val one: MST.Numeric get() = MstRing.one - override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun number(value: Number): MST.Numeric = MstRing.number(value) - override fun add(left: MST, right: MST): MST.Binary = MstRing.add(left, right) + public override fun bindSymbolOrNull(value: String): MST.Symbolic = MstAlgebra.bindSymbolOrNull(value) + public override fun number(value: Number): MST.Numeric = MstRing.number(value) + public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) - override fun scale(a: MST, value: Double): MST.Binary = - MstGroup.binaryOperationFunction(RingOps.TIMES_OPERATION)(a, MstGroup.number(value)) + public override fun scale(a: MST, value: Double): MST.Binary = + MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - override fun multiply(left: MST, right: MST): MST.Binary = MstRing.multiply(left, right) - override fun divide(left: MST, right: MST): MST.Binary = - binaryOperationFunction(FieldOps.DIV_OPERATION)(left, right) + public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) + public override fun divide(a: MST, b: MST): MST.Binary = + binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) - override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } - override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } - override operator fun MST.minus(arg: MST): MST.Binary = MstRing { this@minus - arg } + public override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } + public override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } + public override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b } - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperationFunction(operation) - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstRing.unaryOperationFunction(operation) } @@ -117,66 +117,43 @@ public object MstField : Field, NumbersAddOps, ScaleOperations { */ @Suppress("OVERRIDE_BY_INLINE") public object MstExtendedField : ExtendedField, NumericAlgebra { - override inline val zero: MST.Numeric get() = MstField.zero - override inline val one: MST.Numeric get() = MstField.one + public override inline val zero: MST.Numeric get() = MstField.zero + public override inline val one: MST.Numeric get() = MstField.one - override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun number(value: Number): MST.Numeric = MstRing.number(value) - override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) - override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) - override fun tan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.TAN_OPERATION)(arg) - override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) - override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) - override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) - override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.SINH_OPERATION)(arg) - override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.COSH_OPERATION)(arg) - override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.TANH_OPERATION)(arg) - override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ASINH_OPERATION)(arg) - override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg) - override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg) - override fun add(left: MST, right: MST): MST.Binary = MstField.add(left, right) - override fun sqrt(arg: MST): MST = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) + public override fun bindSymbolOrNull(value: String): MST.Symbolic = MstAlgebra.bindSymbolOrNull(value) + public override fun number(value: Number): MST.Numeric = MstRing.number(value) + public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) + public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) + public override fun tan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.TAN_OPERATION)(arg) + public override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) + public override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) + public override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) + public override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.SINH_OPERATION)(arg) + public override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.COSH_OPERATION)(arg) + public override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.TANH_OPERATION)(arg) + public override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ASINH_OPERATION)(arg) + public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg) + public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg) + public override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b) - override fun scale(a: MST, value: Double): MST = - binaryOperation(GroupOps.PLUS_OPERATION, a, number(value)) + public override fun scale(a: MST, value: Double): MST = + binaryOperation(GroupOperations.PLUS_OPERATION, a, number(value)) - override fun multiply(left: MST, right: MST): MST.Binary = MstField.multiply(left, right) - override fun divide(left: MST, right: MST): MST.Binary = MstField.divide(left, right) - override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus } - override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus } - override operator fun MST.minus(arg: MST): MST.Binary = MstField { this@minus - arg } + public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) + public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) + public override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus } + public override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus } + public override operator fun MST.minus(b: MST): MST.Binary = MstField { this@minus - b } - override fun power(arg: MST, pow: Number): MST.Binary = + public override fun power(arg: MST, pow: Number): MST.Binary = binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) - override fun exp(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - override fun ln(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) + public override fun exp(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) + public override fun ln(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstField.binaryOperationFunction(operation) - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstField.unaryOperationFunction(operation) } - -/** - * Logic algebra for [MST] - */ -@UnstableKMathAPI -public object MstLogicAlgebra : LogicAlgebra { - override fun bindSymbolOrNull(value: String): MST = super.bindSymbolOrNull(value) ?: StringSymbol(value) - - override fun const(boolean: Boolean): Symbol = if (boolean) { - LogicAlgebra.TRUE - } else { - LogicAlgebra.FALSE - } - - override fun MST.not(): MST = MST.Unary(Boolean::not.name, this) - - override fun MST.and(other: MST): MST = MST.Binary(Boolean::and.name, this, other) - - override fun MST.or(other: MST): MST = MST.Binary(Boolean::or.name, this, other) - - override fun MST.xor(other: MST): MST = MST.Binary(Boolean::xor.name, this, other) -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt deleted file mode 100644 index 5d047d5b7..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.expressions - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.structures.getOrNull - -public class NamedMatrix(public val values: Matrix, public val indexer: SymbolIndexer) : Matrix by values { - public operator fun get(i: Symbol, j: Symbol): T = get(indexer.indexOf(i), indexer.indexOf(j)) - - public companion object { - - @OptIn(PerformancePitfall::class) - public fun toStringWithSymbols(values: Matrix<*>, indexer: SymbolIndexer): String = buildString { - appendLine(indexer.symbols.joinToString(separator = "\t", prefix = "\t\t")) - indexer.symbols.forEach { i -> - append(i.identity + "\t") - values.rows.getOrNull(indexer.indexOf(i))?.let { row -> - indexer.symbols.forEach { j -> - append(row.getOrNull(indexer.indexOf(j)).toString()) - append("\t") - } - appendLine() - } - } - } - } -} - -public fun Matrix.named(indexer: SymbolIndexer): NamedMatrix = NamedMatrix(this, indexer) - -public fun Matrix.named(symbols: List): NamedMatrix = named(SimpleSymbolIndexer(symbols)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt index 2bb5043b7..09a5faa12 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt @@ -1,12 +1,13 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.expressions -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.structures.asBuffer import kotlin.contracts.InvocationKind @@ -59,9 +60,9 @@ public fun DerivationResult.grad(vararg variables: Symbol): Point>( public val context: F, bindings: Map, -) : Field>, ExpressionAlgebra>, NumbersAddOps> { - override val zero: AutoDiffValue get() = const(context.zero) - override val one: AutoDiffValue get() = const(context.one) +) : Field>, ExpressionAlgebra>, NumbersAddOperations> { + public override val zero: AutoDiffValue get() = const(context.zero) + public override val one: AutoDiffValue get() = const(context.one) // this stack contains pairs of blocks and values to apply them to private var stack: Array = arrayOfNulls(8) @@ -119,6 +120,8 @@ public open class SimpleAutoDiffField>( get() = getDerivative(this) set(value) = setDerivative(this, value) + public inline fun const(block: F.() -> T): AutoDiffValue = const(context.block()) + /** * Performs update of derivative after the rest of the formula in the back-pass. * @@ -149,17 +152,17 @@ public open class SimpleAutoDiffField>( // // Overloads for Double constants // -// override operator fun Number.plus(b: AutoDiffValue): AutoDiffValue = +// public override operator fun Number.plus(b: AutoDiffValue): AutoDiffValue = // derive(const { this@plus.toDouble() * one + b.value }) { z -> // b.d += z.d // } // -// override operator fun AutoDiffValue.plus(b: Number): AutoDiffValue = b.plus(this) +// public override operator fun AutoDiffValue.plus(b: Number): AutoDiffValue = b.plus(this) // -// override operator fun Number.minus(b: AutoDiffValue): AutoDiffValue = +// public override operator fun Number.minus(b: AutoDiffValue): AutoDiffValue = // derive(const { this@minus.toDouble() * one - b.value }) { z -> b.d -= z.d } // -// override operator fun AutoDiffValue.minus(b: Number): AutoDiffValue = +// public override operator fun AutoDiffValue.minus(b: Number): AutoDiffValue = // derive(const { this@minus.value - one * b.toDouble() }) { z -> d += z.d } @@ -168,35 +171,30 @@ public open class SimpleAutoDiffField>( // Basic math (+, -, *, /) - override fun add(left: AutoDiffValue, right: AutoDiffValue): AutoDiffValue = - derive(const { left.value + right.value }) { z -> - left.d += z.d - right.d += z.d + public override fun add(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + derive(const { a.value + b.value }) { z -> + a.d += z.d + b.d += z.d } - override fun multiply(left: AutoDiffValue, right: AutoDiffValue): AutoDiffValue = - derive(const { left.value * right.value }) { z -> - left.d += z.d * right.value - right.d += z.d * left.value + public override fun multiply(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + derive(const { a.value * b.value }) { z -> + a.d += z.d * b.value + b.d += z.d * a.value } - override fun divide(left: AutoDiffValue, right: AutoDiffValue): AutoDiffValue = - derive(const { left.value / right.value }) { z -> - left.d += z.d / right.value - right.d -= z.d * left.value / (right.value * right.value) + public override fun divide(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + derive(const { a.value / b.value }) { z -> + a.d += z.d / b.value + b.d -= z.d * a.value / (b.value * b.value) } - override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = + public override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = derive(const { value * a.value }) { z -> a.d += z.d * value } } -public inline fun > SimpleAutoDiffField.const(block: F.() -> T): AutoDiffValue { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return const(context.block()) -} - /** * Runs differentiation and establishes [SimpleAutoDiffField] context inside the block of code. @@ -211,7 +209,7 @@ public inline fun > SimpleAutoDiffField.const(block: * assertEquals(9.0, x.d) // dy/dx * ``` * - * @param body the action in [SimpleAutoDiffField] context returning [AutoDiffValue] to differentiate with respect to. + * @param body the action in [SimpleAutoDiffField] context returning [AutoDiffVariable] to differentiate with respect to. * @return the result of differentiation. */ public fun > F.simpleAutoDiff( @@ -235,13 +233,13 @@ public fun > F.simpleAutoDiff( public class SimpleAutoDiffExpression>( public val field: F, public val function: SimpleAutoDiffField.() -> AutoDiffValue, -) : FirstDerivativeExpression() { - override operator fun invoke(arguments: Map): T { +) : FirstDerivativeExpression>() { + public override operator fun invoke(arguments: Map): T { //val bindings = arguments.entries.map { it.key.bind(it.value) } return SimpleAutoDiffField(field, arguments).function().value } - override fun derivativeOrNull(symbol: Symbol): Expression = Expression { arguments -> + public override fun derivativeOrNull(symbol: Symbol): Expression = Expression { arguments -> //val bindings = arguments.entries.map { it.key.bind(it.value) } val derivationResult = SimpleAutoDiffField(field, arguments).differentiate(function) derivationResult.derivative(symbol) @@ -251,9 +249,7 @@ public class SimpleAutoDiffExpression>( /** * Generate [AutoDiffProcessor] for [SimpleAutoDiffExpression] */ -public fun > simpleAutoDiff( - field: F, -): AutoDiffProcessor, SimpleAutoDiffField> = +public fun > simpleAutoDiff(field: F): AutoDiffProcessor, SimpleAutoDiffField, Expression> = AutoDiffProcessor { function -> SimpleAutoDiffExpression(field, function) } @@ -272,8 +268,8 @@ public fun > SimpleAutoDiffField.sqrt(x: Aut public fun > SimpleAutoDiffField.pow( x: AutoDiffValue, y: Double, -): AutoDiffValue = derive(const { x.value.pow(y) }) { z -> - x.d += z.d * y * x.value.pow(y - 1) +): AutoDiffValue = derive(const { power(x.value, y) }) { z -> + x.d += z.d * y * power(x.value, y - 1) } public fun > SimpleAutoDiffField.pow( @@ -343,30 +339,33 @@ public fun > SimpleAutoDiffField.atanh(x: Au public class SimpleAutoDiffExtendedField>( context: F, bindings: Map, -) : ExtendedField>, ScaleOperations>, SimpleAutoDiffField(context, bindings) { +) : ExtendedField>, ScaleOperations>, + SimpleAutoDiffField(context, bindings) { - override fun number(value: Number): AutoDiffValue = const { number(value) } + override fun bindSymbol(value: String): AutoDiffValue = super.bindSymbol(value) - override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = a * number(value) + public override fun number(value: Number): AutoDiffValue = const { number(value) } + + public override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = a * number(value) // x ^ 2 public fun sqr(x: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sqr(x) // x ^ 1/2 - override fun sqrt(arg: AutoDiffValue): AutoDiffValue = + public override fun sqrt(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sqrt(arg) // x ^ y (const) - override fun power(arg: AutoDiffValue, pow: Number): AutoDiffValue = + public override fun power(arg: AutoDiffValue, pow: Number): AutoDiffValue = (this as SimpleAutoDiffField).pow(arg, pow.toDouble()) // exp(x) - override fun exp(arg: AutoDiffValue): AutoDiffValue = + public override fun exp(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).exp(arg) // ln(x) - override fun ln(arg: AutoDiffValue): AutoDiffValue = + public override fun ln(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).ln(arg) // x ^ y (any) @@ -376,40 +375,40 @@ public class SimpleAutoDiffExtendedField>( ): AutoDiffValue = exp(y * ln(x)) // sin(x) - override fun sin(arg: AutoDiffValue): AutoDiffValue = + public override fun sin(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sin(arg) // cos(x) - override fun cos(arg: AutoDiffValue): AutoDiffValue = + public override fun cos(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).cos(arg) - override fun tan(arg: AutoDiffValue): AutoDiffValue = + public override fun tan(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).tan(arg) - override fun asin(arg: AutoDiffValue): AutoDiffValue = + public override fun asin(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).asin(arg) - override fun acos(arg: AutoDiffValue): AutoDiffValue = + public override fun acos(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).acos(arg) - override fun atan(arg: AutoDiffValue): AutoDiffValue = + public override fun atan(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).atan(arg) - override fun sinh(arg: AutoDiffValue): AutoDiffValue = + public override fun sinh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sinh(arg) - override fun cosh(arg: AutoDiffValue): AutoDiffValue = + public override fun cosh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).cosh(arg) - override fun tanh(arg: AutoDiffValue): AutoDiffValue = + public override fun tanh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).tanh(arg) - override fun asinh(arg: AutoDiffValue): AutoDiffValue = + public override fun asinh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).asinh(arg) - override fun acosh(arg: AutoDiffValue): AutoDiffValue = + public override fun acosh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).acosh(arg) - override fun atanh(arg: AutoDiffValue): AutoDiffValue = + public override fun atanh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).atanh(arg) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt deleted file mode 100644 index c57ce69ab..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.expressions - -import kotlin.jvm.JvmInline -import kotlin.properties.ReadOnlyProperty - -/** - * A marker interface for a symbol. A symbol must have an identity with equality relation based on it. - * Other properties are to store additional, transient data only. - */ -public interface Symbol : MST { - /** - * Identity object for the symbol. Two symbols with the same identity are considered to be the same symbol. - */ - public val identity: String - - public companion object { - public val x: Symbol = Symbol("x") - public val xError: Symbol = Symbol("x.error") - public val y: Symbol = Symbol("y") - public val yError: Symbol = Symbol("y.error") - public val z: Symbol = Symbol("z") - public val zError: Symbol = Symbol("z.error") - } -} - -/** - * A [Symbol] with a [String] identity - */ -@JvmInline -internal value class StringSymbol(override val identity: String) : Symbol { - override fun toString(): String = identity -} - -/** - * Create s Symbols with a string identity - */ -public fun Symbol(identity: String): Symbol = StringSymbol(identity) - -/** - * A delegate to create a symbol with a string identity in this scope - */ -public val symbol: ReadOnlyProperty = ReadOnlyProperty { _, property -> - StringSymbol(property.name) -} - -/** - * Ger a value from a [String]-keyed map by a [Symbol] - */ -public operator fun Map.get(symbol: Symbol): T? = get(symbol.identity) - -/** - * Set a value of [String]-keyed map by a [Symbol] - */ -public operator fun MutableMap.set(symbol: Symbol, value: T) { - set(symbol.identity, value) -} - -/** - * Get a value from a [Symbol]-keyed map by a [String] - */ -public operator fun Map.get(string: String): T? = get(StringSymbol(string)) - -/** - * Set a value of [String]-keyed map by a [Symbol] - */ -public operator fun MutableMap.set(string: String, value: T) { - set(StringSymbol(string), value) -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt index 7112e921a..886008983 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt @@ -1,17 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.expressions -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract import kotlin.jvm.JvmInline /** @@ -35,12 +33,12 @@ public interface SymbolIndexer { public operator fun DoubleArray.get(symbol: Symbol): Double { require(size == symbols.size) { "The input array size for indexer should be ${symbols.size} but $size found" } - return get(indexOf(symbol)) + return get(this@SymbolIndexer.indexOf(symbol)) } public operator fun Point.get(symbol: Symbol): T { require(size == symbols.size) { "The input buffer size for indexer should be ${symbols.size} but $size found" } - return get(indexOf(symbol)) + return get(this@SymbolIndexer.indexOf(symbol)) } public fun DoubleArray.toMap(): Map { @@ -48,11 +46,6 @@ public interface SymbolIndexer { return symbols.indices.associate { symbols[it] to get(it) } } - public fun Point.toMap(): Map { - require(size == symbols.size) { "The input array size for indexer should be ${symbols.size} but $size found" } - return symbols.indices.associate { symbols[it] to get(it) } - } - public operator fun Structure2D.get(rowSymbol: Symbol, columnSymbol: Symbol): T = get(indexOf(rowSymbol), indexOf(columnSymbol)) @@ -62,10 +55,6 @@ public interface SymbolIndexer { public fun Map.toPoint(bufferFactory: BufferFactory): Point = bufferFactory(symbols.size) { getValue(symbols[it]) } - public fun Map.toPoint(): DoubleBuffer = - DoubleBuffer(symbols.size) { getValue(symbols[it]) } - - public fun Map.toDoubleArray(): DoubleArray = DoubleArray(symbols.size) { getValue(symbols[it]) } } @@ -77,13 +66,9 @@ public value class SimpleSymbolIndexer(override val symbols: List) : Sym * Execute the block with symbol indexer based on given symbol order */ @UnstableKMathAPI -public inline fun withSymbols(vararg symbols: Symbol, block: SymbolIndexer.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return with(SimpleSymbolIndexer(symbols.toList()), block) -} +public inline fun withSymbols(vararg symbols: Symbol, block: SymbolIndexer.() -> R): R = + with(SimpleSymbolIndexer(symbols.toList()), block) @UnstableKMathAPI -public inline fun withSymbols(symbols: Collection, block: SymbolIndexer.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return with(SimpleSymbolIndexer(symbols.toList()), block) -} +public inline fun withSymbols(symbols: Collection, block: SymbolIndexer.() -> R): R = + with(SimpleSymbolIndexer(symbols.toList()), block) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/expressionBuilders.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/expressionBuilders.kt new file mode 100644 index 000000000..142194070 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/expressionBuilders.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.expressions + +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.Ring +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + + +/** + * Creates a functional expression with this [Ring]. + */ +public inline fun Ring.spaceExpression(block: FunctionalExpressionGroup>.() -> Expression): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionGroup(this).block() +} + +/** + * Creates a functional expression with this [Ring]. + */ +public inline fun Ring.ringExpression(block: FunctionalExpressionRing>.() -> Expression): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionRing(this).block() +} + +/** + * Creates a functional expression with this [Field]. + */ +public inline fun Field.fieldExpression(block: FunctionalExpressionField>.() -> Expression): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionField(this).block() +} + +/** + * Creates a functional expression with this [ExtendedField]. + */ +public inline fun ExtendedField.extendedFieldExpression(block: FunctionalExpressionExtendedField>.() -> Expression): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionExtendedField(this).block() +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt index 4bba47a91..62d2408e3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt @@ -1,44 +1,47 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear -import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.VirtualBuffer import space.kscience.kmath.structures.indices -public class BufferedLinearSpace>( - private val bufferAlgebra: BufferAlgebra, +public class BufferedLinearSpace>( + override val elementAlgebra: A, + private val bufferFactory: BufferFactory, ) : LinearSpace { - override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra - private val ndAlgebra = BufferedRingOpsND(bufferAlgebra) + private fun ndRing( + rows: Int, + cols: Int, + ): BufferedRingND = AlgebraND.ring(elementAlgebra, bufferFactory, rows, cols) override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix = - ndAlgebra.structureND(ShapeND(rows, columns)) { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() + ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() override fun buildVector(size: Int, initializer: A.(Int) -> T): Point = - bufferAlgebra.buffer(size) { elementAlgebra.initializer(it) } + bufferFactory(size) { elementAlgebra.initializer(it) } - @OptIn(PerformancePitfall::class) - override fun Matrix.unaryMinus(): Matrix = ndAlgebra { - asND().map { -it }.as2D() + override fun Matrix.unaryMinus(): Matrix = ndRing(rowNum, colNum).run { + unwrap().map { -it }.as2D() } - override fun Matrix.plus(other: Matrix): Matrix = ndAlgebra { + override fun Matrix.plus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } - asND().plus(other.asND()).as2D() + unwrap().plus(other.unwrap()).as2D() } - override fun Matrix.minus(other: Matrix): Matrix = ndAlgebra { + override fun Matrix.minus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } - asND().minus(other.asND()).as2D() + unwrap().minus(other.unwrap()).as2D() } private fun Buffer.linearize() = if (this is VirtualBuffer) { @@ -47,7 +50,6 @@ public class BufferedLinearSpace>( this } - @OptIn(PerformancePitfall::class) override fun Matrix.dot(other: Matrix): Matrix { require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } return elementAlgebra { @@ -65,7 +67,6 @@ public class BufferedLinearSpace>( } } - @OptIn(PerformancePitfall::class) override fun Matrix.dot(vector: Point): Point { require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } return elementAlgebra { @@ -81,12 +82,7 @@ public class BufferedLinearSpace>( } } - @OptIn(PerformancePitfall::class) - override fun Matrix.times(value: T): Matrix = ndAlgebra { - asND().map { it * value }.as2D() + override fun Matrix.times(value: T): Matrix = ndRing(rowNum, colNum).run { + unwrap().map { it * value }.as2D() } -} - - -public val > A.linearSpace: BufferedLinearSpace - get() = BufferedLinearSpace(BufferRingOps(this)) +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt deleted file mode 100644 index 940af4a86..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleBufferOps -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer - -public object DoubleLinearSpace : LinearSpace { - - override val elementAlgebra: DoubleField get() = DoubleField - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double - ): Matrix = DoubleFieldOpsND.structureND(ShapeND(rows, columns)) { (i, j) -> - DoubleField.initializer(i, j) - }.as2D() - - override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): DoubleBuffer = - DoubleBuffer(size) { DoubleField.initializer(it) } - - override fun Matrix.unaryMinus(): Matrix = DoubleFieldOpsND { - asND().map { -it }.as2D() - } - - override fun Matrix.plus(other: Matrix): Matrix = DoubleFieldOpsND { - require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } - asND().plus(other.asND()).as2D() - } - - override fun Matrix.minus(other: Matrix): Matrix = DoubleFieldOpsND { - require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } - asND().minus(other.asND()).as2D() - } - - // Create a continuous in-memory representation of this vector for better memory layout handling - private fun Buffer.linearize() = if (this is DoubleBuffer) { - this.array - } else { - DoubleArray(size) { get(it) } - } - - @OptIn(PerformancePitfall::class) - override fun Matrix.dot(other: Matrix): Matrix { - require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } - val rows = this@dot.rows.map { it.linearize() } - val columns = other.columns.map { it.linearize() } - return buildMatrix(rowNum, other.colNum) { i, j -> - val r = rows[i] - val c = columns[j] - var res = 0.0 - for (l in r.indices) { - res += r[l] * c[l] - } - res - } - } - - @OptIn(PerformancePitfall::class) - override fun Matrix.dot(vector: Point): DoubleBuffer { - require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } - val rows = this@dot.rows.map { it.linearize() } - return DoubleBuffer(rowNum) { i -> - val r = rows[i] - var res = 0.0 - for (j in r.indices) { - res += r[j] * vector[j] - } - res - } - - } - - override fun Matrix.times(value: Double): Matrix = DoubleFieldOpsND { - asND().map { it * value }.as2D() - } - - public override fun Point.plus(other: Point): DoubleBuffer = DoubleBufferOps.run { - this@plus + other - } - - public override fun Point.minus(other: Point): DoubleBuffer = DoubleBufferOps.run { - this@minus - other - } - - public override fun Point.times(value: Double): DoubleBuffer = DoubleBufferOps.run { - scale(this@times, value) - } - - public operator fun Point.div(value: Double): DoubleBuffer = DoubleBufferOps.run { - scale(this@div, 1.0 / value) - } - - public override fun Double.times(v: Point): DoubleBuffer = v * this - - -} - -public val DoubleField.linearSpace: DoubleLinearSpace get() = DoubleLinearSpace diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt index af9ebb463..9c3ffd819 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt @@ -1,13 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear +import space.kscience.kmath.nd.as1D + /** - * A group of methods to solve for *X* in equation *X = A−1 · B*, where *A* and *B* are - * matrices or vectors. + * A group of methods to solve for *X* in equation *X = A -1 · B*, where *A* and *B* are matrices or + * vectors. * * @param T the type of items. */ @@ -28,3 +30,20 @@ public interface LinearSolver { public fun inverse(matrix: Matrix): Matrix } +/** + * Convert matrix to vector if it is possible. + */ +public fun Matrix.asVector(): Point = + if (this.colNum == 1) + as1D() + else + error("Can't convert matrix with more than one column to vector") + +/** + * Creates an n × 1 [VirtualMatrix], where n is the size of the given buffer. + * + * @param T the type of elements contained in the buffer. + * @receiver a buffer. + * @return the new matrix. + */ +public fun Point.asMatrix(): VirtualMatrix = VirtualMatrix(size, 1) { i, _ -> get(i) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index a82bafe57..0798e8763 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt @@ -1,19 +1,16 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.MutableStructure2D -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.operations.BufferRingOps -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferFactory +import space.kscience.kmath.structures.DoubleBuffer import kotlin.reflect.KClass /** @@ -22,7 +19,6 @@ import kotlin.reflect.KClass * @param T the type of items. */ public typealias Matrix = Structure2D -public typealias MutableMatrix = MutableStructure2D /** * Alias or using [Buffer] as a point/vector in a many-dimensional space. @@ -32,12 +28,12 @@ public typealias MutableMatrix = MutableStructure2D public typealias Point = Buffer /** - * Basic operations on matrices and vectors. + * Basic operations on matrices and vectors. Operates on [Matrix]. * * @param T the type of items in the matrices. - * @param A the type of ring over [T]. + * @param M the type of operated matrices. */ -public interface LinearSpace> { +public interface LinearSpace> { public val elementAlgebra: A /** @@ -167,7 +163,7 @@ public interface LinearSpace> { public operator fun T.times(v: Point): Point = v * this /** - * Compute a feature of the structure in this scope. Structure features take precedence other context features. + * Get a feature of the structure in this scope. Structure features take precedence other context features * * @param F the type of feature. * @param structure the structure. @@ -175,8 +171,7 @@ public interface LinearSpace> { * @return a feature object or `null` if it isn't present. */ @UnstableKMathAPI - public fun computeFeature(structure: Matrix, type: KClass): F? = - structure.getFeature(type) + public fun getFeature(structure: Matrix, type: KClass): F? = structure.getFeature(type) public companion object { @@ -184,39 +179,31 @@ public interface LinearSpace> { * A structured matrix with custom buffer */ public fun > buffered( - algebra: A - ): LinearSpace = BufferedLinearSpace(BufferRingOps(algebra)) + algebra: A, + bufferFactory: BufferFactory = Buffer.Companion::boxing, + ): LinearSpace = BufferedLinearSpace(algebra, bufferFactory) + public val real: LinearSpace = buffered(DoubleField, ::DoubleBuffer) + + /** + * Automatic buffered matrix, unboxed if it is possible + */ + public inline fun > auto(ring: A): LinearSpace = + buffered(ring, Buffer.Companion::auto) } } /** - * Get a feature of the structure in this scope. Structure features take precedence other context features. + * Get a feature of the structure in this scope. Structure features take precedence other context features * * @param T the type of items in the matrices. * @param F the type of feature. * @return a feature object or `null` if it isn't present. */ @UnstableKMathAPI -public inline fun LinearSpace.computeFeature(structure: Matrix): F? = - computeFeature(structure, F::class) +public inline fun LinearSpace.getFeature(structure: Matrix): F? = + getFeature(structure, F::class) -public inline operator fun , R> LS.invoke(block: LS.() -> R): R = run(block) +public operator fun , R> LS.invoke(block: LS.() -> R): R = run(block) - -/** - * Convert matrix to vector if it is possible. - */ -public fun Matrix.asVector(): Point = - if (this.colNum == 1) as1D() - else error("Can't convert matrix with more than one column to vector") - -/** - * Creates an n × 1 [VirtualMatrix], where n is the size of the given buffer. - * - * @param T the type of elements contained in the buffer. - * @receiver a buffer. - * @return the new matrix. - */ -public fun Point.asMatrix(): VirtualMatrix = VirtualMatrix(size, 1) { i, _ -> get(i) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt index 650e7be5c..f3653d394 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt @@ -1,11 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.getFeature import space.kscience.kmath.operations.* import space.kscience.kmath.structures.BufferAccessor2D import space.kscience.kmath.structures.DoubleBuffer @@ -33,7 +34,7 @@ public class LupDecomposition( j == i -> elementContext.one else -> elementContext.zero } - }.withFeature(LFeature) + } + LFeature /** @@ -43,7 +44,7 @@ public class LupDecomposition( */ override val u: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> if (j >= i) lu[i, j] else elementContext.zero - }.withFeature(UFeature) + } + UFeature /** * Returns the P rows permutation matrix. @@ -81,7 +82,7 @@ public fun > LinearSpace>.lup( val m = matrix.colNum val pivot = IntArray(matrix.rowNum) - //TODO just waits for multi-receivers + //TODO just waits for KEEP-176 BufferAccessor2D(matrix.rowNum, matrix.colNum, factory).run { elementAlgebra { val lu = create(matrix) @@ -113,7 +114,7 @@ public fun > LinearSpace>.lup( for (i in 0 until col) sum -= luRow[i] * lu[i, col] luRow[col] = sum - // maintain the best permutation choice + // maintain best permutation choice if (abs(sum) > largest) { largest = abs(sum) max = row @@ -155,13 +156,10 @@ public inline fun > LinearSpace>.lup( noinline checkSingular: (T) -> Boolean, ): LupDecomposition = lup(MutableBuffer.Companion::auto, matrix, checkSingular) -public fun LinearSpace.lup( - matrix: Matrix, - singularityThreshold: Double = 1e-11, -): LupDecomposition = - lup(::DoubleBuffer, matrix) { it < singularityThreshold } +public fun LinearSpace.lup(matrix: Matrix): LupDecomposition = + lup(::DoubleBuffer, matrix) { it < 1e-11 } -internal fun LupDecomposition.solve( +public fun LupDecomposition.solveWithLup( factory: MutableBufferFactory, matrix: Matrix, ): Matrix { @@ -209,22 +207,41 @@ internal fun LupDecomposition.solve( } } +public inline fun LupDecomposition.solveWithLup(matrix: Matrix): Matrix = + solveWithLup(MutableBuffer.Companion::auto, matrix) + /** - * Produce a generic solver based on LUP decomposition + * Solves a system of linear equations *ax = b** using LUP decomposition. */ @OptIn(UnstableKMathAPI::class) -public fun , F : Field> LinearSpace.lupSolver( - bufferFactory: MutableBufferFactory, - singularityCheck: (T) -> Boolean, -): LinearSolver = object : LinearSolver { - override fun solve(a: Matrix, b: Matrix): Matrix { - // Use existing decomposition if it is provided by matrix - val decomposition = computeFeature(a) ?: lup(bufferFactory, a, singularityCheck) - return decomposition.solve(bufferFactory, b) - } - - override fun inverse(matrix: Matrix): Matrix = solve(matrix, one(matrix.rowNum, matrix.colNum)) +public inline fun > LinearSpace>.solveWithLup( + a: Matrix, + b: Matrix, + noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, + noinline checkSingular: (T) -> Boolean, +): Matrix { + // Use existing decomposition if it is provided by matrix + val decomposition = a.getFeature() ?: lup(bufferFactory, a, checkSingular) + return decomposition.solveWithLup(bufferFactory, b) } -public fun LinearSpace.lupSolver(singularityThreshold: Double = 1e-11): LinearSolver = - lupSolver(::DoubleBuffer) { it < singularityThreshold } +public inline fun > LinearSpace>.inverseWithLup( + matrix: Matrix, + noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, + noinline checkSingular: (T) -> Boolean, +): Matrix = solveWithLup(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) + + +@OptIn(UnstableKMathAPI::class) +public fun LinearSpace.solveWithLup(a: Matrix, b: Matrix): Matrix { + // Use existing decomposition if it is provided by matrix + val bufferFactory: MutableBufferFactory = ::DoubleBuffer + val decomposition: LupDecomposition = a.getFeature() ?: lup(bufferFactory, a) { it < 1e-11 } + return decomposition.solveWithLup(bufferFactory, b) +} + +/** + * Inverses a square matrix using LUP decomposition. Non square matrix will throw a error. + */ +public fun LinearSpace.inverseWithLup(matrix: Matrix): Matrix = + solveWithLup(matrix, one(matrix.rowNum, matrix.colNum)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt index 4d2f01e68..e6115a1e5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt @@ -1,16 +1,14 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring -import space.kscience.kmath.structures.BufferAccessor2D -import space.kscience.kmath.structures.MutableBuffer -public class MatrixBuilder>( +public class MatrixBuilder>( public val linearSpace: LinearSpace, public val rows: Int, public val columns: Int, @@ -47,31 +45,4 @@ public inline fun LinearSpace>.column( crossinline builder: (Int) -> T, ): Matrix = buildMatrix(size, 1) { i, _ -> builder(i) } -public fun LinearSpace>.column(vararg values: T): Matrix = column(values.size, values::get) - -public object SymmetricMatrixFeature : MatrixFeature - -/** - * Naive implementation of a symmetric matrix builder, that adds a [SymmetricMatrixFeature] tag. The resulting matrix contains - * full `size^2` number of elements, but caches elements during calls to save [builder] calls. [builder] is always called in the - * upper triangle region meaning that `i <= j` - */ -public fun > MatrixBuilder.symmetric( - builder: (i: Int, j: Int) -> T, -): Matrix { - require(columns == rows) { "In order to build symmetric matrix, number of rows $rows should be equal to number of columns $columns" } - return with(BufferAccessor2D(rows, rows, MutableBuffer.Companion::boxing)) { - val cache = factory(rows * rows) { null } - linearSpace.buildMatrix(rows, rows) { i, j -> - val cached = cache[i, j] - if (cached == null) { - val value = if (i <= j) builder(i, j) else builder(j, i) - cache[i, j] = value - cache[j, i] = value - value - } else { - cached - } - }.withFeature(SymmetricMatrixFeature) - } -} \ No newline at end of file +public fun LinearSpace>.column(vararg values: T): Matrix = column(values.size, values::get) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt index ce7acdcba..4a0ca7dfe 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -31,11 +31,11 @@ public object ZeroFeature : DiagonalFeature public object UnitFeature : DiagonalFeature /** - * Matrices with this feature can be inverted: *[inverse] = a−1* where *a* is the owning matrix. + * Matrices with this feature can be inverted: [inverse] = `a`-1 where `a` is the owning matrix. * * @param T the type of matrices' items. */ -public interface InverseMatrixFeature : MatrixFeature { +public interface InverseMatrixFeature : MatrixFeature { /** * The inverse matrix of the matrix that owns this feature. */ @@ -47,7 +47,7 @@ public interface InverseMatrixFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface DeterminantFeature : MatrixFeature { +public interface DeterminantFeature : MatrixFeature { /** * The determinant of the matrix that owns this feature. */ @@ -75,30 +75,13 @@ public object LFeature : MatrixFeature */ public object UFeature : MatrixFeature -/** - * Matrices with this feature support LU factorization: *a = [l] · [u]* where *a* is the owning matrix. - * - * @param T the type of matrices' items. - */ -public interface LUDecompositionFeature : MatrixFeature { - /** - * The lower triangular matrix in this decomposition. It may have [LFeature]. - */ - public val l: Matrix - - /** - * The upper triangular matrix in this decomposition. It may have [UFeature]. - */ - public val u: Matrix -} - /** * Matrices with this feature support LU factorization with partial pivoting: *[p] · a = [l] · [u]* where * *a* is the owning matrix. * * @param T the type of matrices' items. */ -public interface LupDecompositionFeature : MatrixFeature { +public interface LupDecompositionFeature : MatrixFeature { /** * The lower triangular matrix in this decomposition. It may have [LFeature]. */ @@ -126,7 +109,7 @@ public object OrthogonalFeature : MatrixFeature * * @param T the type of matrices' items. */ -public interface QRDecompositionFeature : MatrixFeature { +public interface QRDecompositionFeature : MatrixFeature { /** * The orthogonal matrix in this decomposition. It may have [OrthogonalFeature]. */ @@ -144,7 +127,7 @@ public interface QRDecompositionFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface CholeskyDecompositionFeature : MatrixFeature { +public interface CholeskyDecompositionFeature : MatrixFeature { /** * The triangular matrix in this decomposition. It may have either [UFeature] or [LFeature]. */ @@ -157,7 +140,7 @@ public interface CholeskyDecompositionFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface SingularValueDecompositionFeature : MatrixFeature { +public interface SingularValueDecompositionFeature : MatrixFeature { /** * The matrix in this decomposition. It is unitary, and it consists from left singular vectors. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt index 46454a584..4d1180c17 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt @@ -1,13 +1,13 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.misc.FeatureSet +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature +import space.kscience.kmath.nd.getFeature import space.kscience.kmath.operations.Ring import kotlin.reflect.KClass @@ -16,20 +16,22 @@ import kotlin.reflect.KClass * * @param T the type of items. */ -public class MatrixWrapper internal constructor( +public class MatrixWrapper internal constructor( public val origin: Matrix, - public val features: FeatureSet, + public val features: Set, ) : Matrix by origin { /** - * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the - * criteria. + * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria */ + @UnstableKMathAPI @Suppress("UNCHECKED_CAST") - override fun getFeature(type: KClass): F? = - features.getFeature(type) ?: origin.getFeature(type) + override fun getFeature(type: KClass): F? = features.singleOrNull { type.isInstance(it) } as? F + ?: origin.getFeature(type) - override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$features)" + override fun toString(): String { + return "MatrixWrapper(matrix=$origin, features=$features)" + } } /** @@ -43,34 +45,31 @@ public val Matrix.origin: Matrix /** * Add a single feature to a [Matrix] */ -public fun Matrix.withFeature(newFeature: MatrixFeature): MatrixWrapper = if (this is MatrixWrapper) { - MatrixWrapper(origin, features.with(newFeature)) +public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixWrapper = if (this is MatrixWrapper) { + MatrixWrapper(origin, features + newFeature) } else { - MatrixWrapper(this, FeatureSet.of(newFeature)) + MatrixWrapper(this, setOf(newFeature)) } -@Deprecated("To be replaced by withFeature") -public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixWrapper = withFeature(newFeature) - /** * Add a collection of features to a [Matrix] */ -public fun Matrix.withFeatures(newFeatures: Iterable): MatrixWrapper = +public operator fun Matrix.plus(newFeatures: Collection): MatrixWrapper = if (this is MatrixWrapper) { - MatrixWrapper(origin, features.with(newFeatures)) + MatrixWrapper(origin, features + newFeatures) } else { - MatrixWrapper(this, FeatureSet.of(newFeatures)) + MatrixWrapper(this, newFeatures.toSet()) } /** - * Diagonal matrix of ones. The matrix is virtual no actual matrix is created. + * Diagonal matrix of ones. The matrix is virtual no actual matrix is created */ public fun LinearSpace>.one( rows: Int, columns: Int, ): Matrix = VirtualMatrix(rows, columns) { i, j -> if (i == j) elementAlgebra.one else elementAlgebra.zero -}.withFeature(UnitFeature) +} + UnitFeature /** @@ -81,14 +80,15 @@ public fun LinearSpace>.zero( columns: Int, ): Matrix = VirtualMatrix(rows, columns) { _, _ -> elementAlgebra.zero -}.withFeature(ZeroFeature) +} + ZeroFeature -public class TransposedFeature(public val original: Matrix) : MatrixFeature +public class TransposedFeature(public val original: Matrix) : MatrixFeature /** * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` */ -@Suppress("UNCHECKED_CAST") @OptIn(UnstableKMathAPI::class) -public fun Matrix.transpose(): Matrix = getFeature(TransposedFeature::class)?.original as? Matrix - ?: VirtualMatrix(colNum, rowNum) { i, j -> get(j, i) }.withFeature(TransposedFeature(this)) +public fun Matrix.transpose(): Matrix = getFeature>()?.original ?: VirtualMatrix( + colNum, + rowNum, +) { i, j -> get(j, i) } + TransposedFeature(this) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt index 55b970f4a..e4c2b49f0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt @@ -1,28 +1,22 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear -import space.kscience.kmath.nd.ShapeND - - /** * The matrix where each element is evaluated each time when is being accessed. * * @property generator the function that provides elements. */ -public class VirtualMatrix( +public class VirtualMatrix( override val rowNum: Int, override val colNum: Int, public val generator: (i: Int, j: Int) -> T, ) : Matrix { - override val shape: ShapeND get() = ShapeND(rowNum, colNum) + override val shape: IntArray get() = intArrayOf(rowNum, colNum) override operator fun get(i: Int, j: Int): T = generator(i, j) } - -public fun MatrixBuilder.virtual(generator: (i: Int, j: Int) -> T): VirtualMatrix = - VirtualMatrix(rows, columns, generator) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt deleted file mode 100644 index bdda674dc..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.misc - -import kotlin.jvm.JvmInline -import kotlin.reflect.KClass - -/** - * An entity that contains a set of features defined by their types - */ -public interface Featured { - public fun getFeature(type: FeatureKey): T? -} - -public typealias FeatureKey = KClass - -public interface Feature> { - - /** - * A key used for extraction - */ - @Suppress("UNCHECKED_CAST") - public val key: FeatureKey - get() = this::class as FeatureKey -} - -/** - * A container for a set of features - */ -@JvmInline -public value class FeatureSet> private constructor(public val features: Map, F>) : Featured { - @Suppress("UNCHECKED_CAST") - override fun getFeature(type: FeatureKey): T? = features[type]?.let { it as T } - - public inline fun getFeature(): T? = getFeature(T::class) - - public fun with(feature: T, type: FeatureKey = feature.key): FeatureSet = - FeatureSet(features + (type to feature)) - - public fun with(other: FeatureSet): FeatureSet = FeatureSet(features + other.features) - - public fun with(vararg otherFeatures: F): FeatureSet = - FeatureSet(features + otherFeatures.associateBy { it.key }) - - public fun with(otherFeatures: Iterable): FeatureSet = - FeatureSet(features + otherFeatures.associateBy { it.key }) - - public operator fun iterator(): Iterator = features.values.iterator() - - override fun toString(): String = features.values.joinToString(prefix = "[ ", postfix = " ]") - - - public companion object { - public fun > of(vararg features: F): FeatureSet = FeatureSet(features.associateBy { it.key }) - public fun > of(features: Iterable): FeatureSet = - FeatureSet(features.associateBy { it.key }) - } -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Symbol.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Symbol.kt new file mode 100644 index 000000000..737acc025 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Symbol.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.misc + +import kotlin.jvm.JvmInline +import kotlin.properties.ReadOnlyProperty + +/** + * A marker interface for a symbol. A symbol mus have an identity + */ +public interface Symbol { + /** + * Identity object for the symbol. Two symbols with the same identity are considered to be the same symbol. + */ + public val identity: String + + public companion object{ + public val x: StringSymbol = StringSymbol("x") + public val y: StringSymbol = StringSymbol("y") + public val z: StringSymbol = StringSymbol("z") + } +} + +/** + * A [Symbol] with a [String] identity + */ +@JvmInline +public value class StringSymbol(override val identity: String) : Symbol { + override fun toString(): String = identity +} + + +/** + * A delegate to create a symbol with a string identity in this scope + */ +public val symbol: ReadOnlyProperty = ReadOnlyProperty { _, property -> + StringSymbol(property.name) +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt new file mode 100644 index 000000000..206e4e000 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.misc + +@RequiresOptIn("This API is unstable and could change in future", RequiresOptIn.Level.WARNING) +public annotation class UnstableKMathAPI diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt deleted file mode 100644 index f630055fa..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.misc - -/** - * The same as [zipWithNext], but includes link between last and first element - */ -public inline fun List.zipWithNextCircular(transform: (a: T, b: T) -> R): List { - if (size < 2) return emptyList() - return indices.map { i -> - if (i == size - 1) { - transform(last(), first()) - } else { - transform(get(i), get(i + 1)) - } - } -} - -public fun List.zipWithNextCircular(): List> = zipWithNextCircular { l, r -> l to r } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt index c05f1a6a9..889eb4f22 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,7 +7,6 @@ package space.kscience.kmath.misc import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer import kotlin.jvm.JvmName /** @@ -35,7 +34,7 @@ public inline fun Iterable.cumulative(initial: R, crossinline operatio public inline fun Sequence.cumulative(initial: R, crossinline operation: (R, T) -> R): Sequence = Sequence { this@cumulative.iterator().cumulative(initial, operation) } -public inline fun List.cumulative(initial: R, crossinline operation: (R, T) -> R): List = +public fun List.cumulative(initial: R, operation: (R, T) -> R): List = iterator().cumulative(initial, operation).asSequence().toList() //Cumulative sum @@ -43,8 +42,8 @@ public inline fun List.cumulative(initial: R, crossinline operation: ( /** * Cumulative sum with custom space */ -public fun Iterable.cumulativeSum(ring: Ring): Iterable = - ring { cumulative(zero) { element: T, sum: T -> sum + element } } +public fun Iterable.cumulativeSum(group: Ring): Iterable = + group { cumulative(zero) { element: T, sum: T -> sum + element } } @JvmName("cumulativeSumOfDouble") public fun Iterable.cumulativeSum(): Iterable = cumulative(0.0) { element, sum -> sum + element } @@ -55,8 +54,8 @@ public fun Iterable.cumulativeSum(): Iterable = cumulative(0) { elemen @JvmName("cumulativeSumOfLong") public fun Iterable.cumulativeSum(): Iterable = cumulative(0L) { element, sum -> sum + element } -public fun Sequence.cumulativeSum(ring: Ring): Sequence = - ring { cumulative(zero) { element: T, sum: T -> sum + element } } +public fun Sequence.cumulativeSum(group: Ring): Sequence = + group { cumulative(zero) { element: T, sum: T -> sum + element } } @JvmName("cumulativeSumOfDouble") public fun Sequence.cumulativeSum(): Sequence = cumulative(0.0) { element, sum -> sum + element } @@ -78,12 +77,3 @@ public fun List.cumulativeSum(): List = cumulative(0) { element, sum - @JvmName("cumulativeSumOfLong") public fun List.cumulativeSum(): List = cumulative(0L) { element, sum -> sum + element } - - -public fun Buffer.cumulativeSum(ring: Ring): Buffer = with(ring) { - var accumulator: T = zero - return bufferFactory(size) { - accumulator += get(it) - accumulator - } -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt deleted file mode 100644 index c7886469f..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.misc - -import space.kscience.kmath.misc.Loggable.Companion.INFO - -public fun interface Loggable { - public fun log(tag: String, block: () -> String) - - public companion object { - public const val INFO: String = "INFO" - - public val console: Loggable = Loggable { tag, block -> - println("[$tag] ${block()}") - } - } -} - -public fun Loggable.log(block: () -> String): Unit = log(INFO, block) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt deleted file mode 100644 index 31b8c0037..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - - -package space.kscience.kmath.misc - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.VirtualBuffer - -/** - * Return a new array filled with buffer indices. Indices order is defined by sorting associated buffer value. - * This feature allows sorting buffer values without reordering its content. - * - * @return Buffer indices, sorted by associated value. - */ -@UnstableKMathAPI -public fun > Buffer.indicesSorted(): IntArray = permSortIndicesWith(compareBy { get(it) }) - -/** - * Create a zero-copy virtual buffer that contains the same elements but in ascending order - */ -@OptIn(UnstableKMathAPI::class) -public fun > Buffer.sorted(): Buffer { - val permutations = indicesSorted() - return VirtualBuffer(size) { this[permutations[it]] } -} - -@UnstableKMathAPI -public fun > Buffer.indicesSortedDescending(): IntArray = - permSortIndicesWith(compareByDescending { get(it) }) - -/** - * Create a zero-copy virtual buffer that contains the same elements but in descending order - */ -@OptIn(UnstableKMathAPI::class) -public fun > Buffer.sortedDescending(): Buffer { - val permutations = indicesSortedDescending() - return VirtualBuffer(size) { this[permutations[it]] } -} - -@UnstableKMathAPI -public fun > Buffer.indicesSortedBy(selector: (V) -> C): IntArray = - permSortIndicesWith(compareBy { selector(get(it)) }) - -@OptIn(UnstableKMathAPI::class) -public fun > Buffer.sortedBy(selector: (V) -> C): Buffer { - val permutations = indicesSortedBy(selector) - return VirtualBuffer(size) { this[permutations[it]] } -} - -@UnstableKMathAPI -public fun > Buffer.indicesSortedByDescending(selector: (V) -> C): IntArray = - permSortIndicesWith(compareByDescending { selector(get(it)) }) - -@OptIn(UnstableKMathAPI::class) -public fun > Buffer.sortedByDescending(selector: (V) -> C): Buffer { - val permutations = indicesSortedByDescending(selector) - return VirtualBuffer(size) { this[permutations[it]] } -} - -@UnstableKMathAPI -public fun Buffer.indicesSortedWith(comparator: Comparator): IntArray = - permSortIndicesWith { i1, i2 -> comparator.compare(get(i1), get(i2)) } - -private fun Buffer.permSortIndicesWith(comparator: Comparator): IntArray { - if (size < 2) return IntArray(size) { 0 } - - /* TODO: optimisation : keep a constant big array of indices (Ex: from 0 to 4096), then create indices - * arrays more efficiently by copying subpart of cached one. For bigger needs, we could copy entire - * cached array, then fill remaining indices manually. Not done for now, because: - * 1. doing it right would require some statistics about common used buffer sizes. - * 2. Some benchmark would be needed to ensure it would really provide better performance - */ - val packedIndices = IntArray(size) { idx -> idx } - - /* TODO: find an efficient way to sort in-place instead, and return directly the IntArray. - * Not done for now, because no standard utility is provided yet. An open issue exists for this. - * See: https://youtrack.jetbrains.com/issue/KT-37860 - */ - return packedIndices.sortedWith(comparator).toIntArray() -} - -/** - * Checks that the [Buffer] is sorted (ascending) and throws [IllegalArgumentException] if it is not. - */ -public fun > Buffer.requireSorted() { - for (i in 0..(size - 2)) { - require(get(i + 1) >= get(i)) { "The buffer is not sorted at index $i" } - } -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt index 91e26cc1b..1b3cb9e0a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt @@ -1,71 +1,70 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.* import kotlin.reflect.KClass +/** + * An exception is thrown when the expected ans actual shape of NDArray differs. + * + * @property expected the expected shape. + * @property actual the actual shape. + */ +public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) : + RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.") + /** * The base interface for all ND-algebra implementations. * * @param T the type of ND-structure element. * @param C the type of the element context. + * @param N the type of the structure. */ -public interface AlgebraND>: Algebra> { +public interface AlgebraND> { + /** + * The shape of ND-structures this algebra operates on. + */ + public val shape: IntArray + /** * The algebra over elements of ND structure. */ - public val elementAlgebra: C + public val elementContext: C /** - * Produces a new [StructureND] using given initializer function. + * Produces a new NDStructure using given initializer function. */ - public fun structureND(shape: ShapeND, initializer: C.(IntArray) -> T): StructureND + public fun produce(initializer: C.(IntArray) -> T): StructureND /** * Maps elements from one structure to another one by applying [transform] to them. */ - @PerformancePitfall("Very slow on remote execution algebras") - public fun StructureND.map(transform: C.(T) -> T): StructureND = structureND(shape) { index -> - elementAlgebra.transform(get(index)) - } + public fun StructureND.map(transform: C.(T) -> T): StructureND /** * Maps elements from one structure to another one by applying [transform] to them alongside with their indices. */ - @PerformancePitfall("Very slow on remote execution algebras") - public fun StructureND.mapIndexed(transform: C.(index: IntArray, T) -> T): StructureND = - structureND(shape) { index -> - elementAlgebra.transform(index, get(index)) - } + public fun StructureND.mapIndexed(transform: C.(index: IntArray, T) -> T): StructureND /** * Combines two structures into one. */ - @PerformancePitfall("Very slow on remote execution algebras") - public fun zip(left: StructureND, right: StructureND, transform: C.(T, T) -> T): StructureND { - require(left.shape.contentEquals(right.shape)) { - "Expected left and right of the same shape, but left - ${left.shape} and right - ${right.shape}" - } - return structureND(left.shape) { index -> - elementAlgebra.transform(left[index], right[index]) - } - } + public fun combine(a: StructureND, b: StructureND, transform: C.(T, T) -> T): StructureND /** * Element-wise invocation of function working on [T] on a [StructureND]. */ - @PerformancePitfall public operator fun Function1.invoke(structure: StructureND): StructureND = structure.map { value -> this@invoke(value) } /** - * Get a feature of the structure in this scope. Structure features take precedence other context features. + * Get a feature of the structure in this scope. Structure features take precedence other context features * * @param F the type of feature. * @param structure the structure. @@ -79,8 +78,9 @@ public interface AlgebraND>: Algebra> { public companion object } + /** - * Get a feature of the structure in this scope. Structure features take precedence other context features. + * Get a feature of the structure in this scope. Structure features take precedence other context features * * @param T the type of items in the matrices. * @param F the type of feature. @@ -90,23 +90,56 @@ public interface AlgebraND>: Algebra> { public inline fun AlgebraND.getFeature(structure: StructureND): F? = getFeature(structure, F::class) +/** + * Checks if given elements are consistent with this context. + * + * @param structures the structures to check. + * @return the array of valid structures. + */ +internal fun > AlgebraND.checkShape(vararg structures: StructureND): Array> = + structures + .map(StructureND::shape) + .singleOrNull { !shape.contentEquals(it) } + ?.let>> { throw ShapeMismatchException(shape, it) } + ?: structures + +/** + * Checks if given element is consistent with this context. + * + * @param element the structure to check. + * @return the valid structure. + */ +internal fun > AlgebraND.checkShape(element: StructureND): StructureND { + if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape) + return element +} + /** * Space of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param A the type of group over structure elements. + * @param N the type of ND structure. + * @param S the type of space of structure elements. */ -public interface GroupOpsND> : GroupOps>, AlgebraND { +public interface GroupND> : Group>, AlgebraND { /** * Element-wise addition. * - * @param left the augend. - * @param right the addend. + * @param a the augend. + * @param b the addend. * @return the sum. */ - @OptIn(PerformancePitfall::class) - override fun add(left: StructureND, right: StructureND): StructureND = - zip(left, right) { aValue, bValue -> add(aValue, bValue) } + public override fun add(a: StructureND, b: StructureND): StructureND = + combine(a, b) { aValue, bValue -> add(aValue, bValue) } + +// /** +// * Element-wise multiplication by scalar. +// * +// * @param a the multiplicand. +// * @param k the multiplier. +// * @return the product. +// */ +// public override fun multiply(a: NDStructure, k: Number): NDStructure = a.map { multiply(it, k) } // TODO move to extensions after KEEP-176 @@ -117,7 +150,6 @@ public interface GroupOpsND> : GroupOps>, * @param arg the addend. * @return the sum. */ - @OptIn(PerformancePitfall::class) public operator fun StructureND.plus(arg: T): StructureND = this.map { value -> add(arg, value) } /** @@ -127,7 +159,6 @@ public interface GroupOpsND> : GroupOps>, * @param arg the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) public operator fun StructureND.minus(arg: T): StructureND = this.map { value -> add(arg, -value) } /** @@ -137,7 +168,6 @@ public interface GroupOpsND> : GroupOps>, * @param arg the addend. * @return the sum. */ - @OptIn(PerformancePitfall::class) public operator fun T.plus(arg: StructureND): StructureND = arg.map { value -> add(this@plus, value) } /** @@ -147,35 +177,30 @@ public interface GroupOpsND> : GroupOps>, * @param arg the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) public operator fun T.minus(arg: StructureND): StructureND = arg.map { value -> add(-this@minus, value) } public companion object } -public interface GroupND> : Group>, GroupOpsND, WithShape { - override val zero: StructureND get() = structureND(shape) { elementAlgebra.zero } -} - /** * Ring of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param A the type of ring over structure elements. + * @param N the type of ND structure. + * @param R the type of ring of structure elements. */ -public interface RingOpsND> : RingOps>, GroupOpsND { +public interface RingND> : Ring>, GroupND { /** * Element-wise multiplication. * - * @param left the multiplicand. - * @param right the multiplier. + * @param a the multiplicand. + * @param b the multiplier. * @return the product. */ - @OptIn(PerformancePitfall::class) - override fun multiply(left: StructureND, right: StructureND): StructureND = - zip(left, right) { aValue, bValue -> multiply(aValue, bValue) } + public override fun multiply(a: StructureND, b: StructureND): StructureND = + combine(a, b) { aValue, bValue -> multiply(aValue, bValue) } - //TODO move to extensions with context receivers + //TODO move to extensions after KEEP-176 /** * Multiplies an ND structure by an element of it. @@ -184,7 +209,6 @@ public interface RingOpsND> : RingOps>, Gro * @param arg the multiplier. * @return the product. */ - @OptIn(PerformancePitfall::class) public operator fun StructureND.times(arg: T): StructureND = this.map { value -> multiply(arg, value) } /** @@ -194,39 +218,30 @@ public interface RingOpsND> : RingOps>, Gro * @param arg the multiplier. * @return the product. */ - @OptIn(PerformancePitfall::class) public operator fun T.times(arg: StructureND): StructureND = arg.map { value -> multiply(this@times, value) } public companion object } -public interface RingND> : Ring>, RingOpsND, GroupND, WithShape { - override val one: StructureND get() = structureND(shape) { elementAlgebra.one } -} - - /** * Field of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param A the type field over structure elements. + * @param N the type of ND structure. + * @param F the type field of structure elements. */ -public interface FieldOpsND> : - FieldOps>, - RingOpsND, - ScaleOperations> { +public interface FieldND> : Field>, RingND, ScaleOperations> { /** * Element-wise division. * - * @param left the dividend. - * @param right the divisor. + * @param a the dividend. + * @param b the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) - override fun divide(left: StructureND, right: StructureND): StructureND = - zip(left, right) { aValue, bValue -> divide(aValue, bValue) } + public override fun divide(a: StructureND, b: StructureND): StructureND = + combine(a, b) { aValue, bValue -> divide(aValue, bValue) } - //TODO move to extensions after https://github.com/Kotlin/KEEP/blob/master/proposals/context-receivers.md + //TODO move to extensions after KEEP-176 /** * Divides an ND structure by an element of it. * @@ -234,7 +249,6 @@ public interface FieldOpsND> : * @param arg the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) public operator fun StructureND.div(arg: T): StructureND = this.map { value -> divide(arg, value) } /** @@ -244,13 +258,35 @@ public interface FieldOpsND> : * @param arg the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) public operator fun T.div(arg: StructureND): StructureND = arg.map { divide(it, this@div) } - @OptIn(PerformancePitfall::class) - override fun scale(a: StructureND, value: Double): StructureND = a.map { scale(it, value) } +// @ThreadLocal +// public companion object { +// private val realNDFieldCache: MutableMap = hashMapOf() +// +// /** +// * Create a nd-field for [Double] values or pull it from cache if it was created previously. +// */ +// public fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) } +// +// /** +// * Create an ND field with boxing generic buffer. +// */ +// public fun > boxing( +// field: F, +// vararg shape: Int, +// bufferFactory: BufferFactory = Buffer.Companion::boxing, +// ): BufferedNDField = BufferedNDField(shape, field, bufferFactory) +// +// /** +// * Create a most suitable implementation for nd-field using reified class. +// */ +// @Suppress("UNCHECKED_CAST") +// public inline fun > auto(field: F, vararg shape: Int): NDField = +// when { +// T::class == Double::class -> real(*shape) as NDField +// T::class == Complex::class -> complex(*shape) as BufferedNDField +// else -> BoxingNDField(shape, field, Buffer.Companion::auto) +// } +// } } - -public interface FieldND> : Field>, FieldOpsND, RingND, WithShape { - override val one: StructureND get() = structureND(shape) { elementAlgebra.one } -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt index 74c63e6e2..905a48d5c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt @@ -1,198 +1,142 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:OptIn(UnstableKMathAPI::class) - package space.kscience.kmath.nd -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferFactory +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract -public interface BufferAlgebraND> : AlgebraND { - public val indexerBuilder: (ShapeND) -> ShapeIndexer - public val bufferAlgebra: BufferAlgebra - override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra +public interface BufferAlgebraND> : AlgebraND { + public val strides: Strides + public val bufferFactory: BufferFactory - override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): BufferND { - val indexer = indexerBuilder(shape) - return BufferND( - indexer, - bufferAlgebra.buffer(indexer.linearSize) { offset -> - elementAlgebra.initializer(indexer.index(offset)) - } - ) - } - - @OptIn(PerformancePitfall::class) - public fun StructureND.toBufferND(): BufferND = when (this) { - is BufferND -> this - else -> { - val indexer = indexerBuilder(shape) - BufferND(indexer, bufferAlgebra.buffer(indexer.linearSize) { offset -> get(indexer.index(offset)) }) + override fun produce(initializer: A.(IntArray) -> T): BufferND = BufferND( + strides, + bufferFactory(strides.linearSize) { offset -> + elementContext.initializer(strides.index(offset)) } + ) + + public val StructureND.buffer: Buffer + get() = when { + !shape.contentEquals(this@BufferAlgebraND.shape) -> throw ShapeMismatchException( + this@BufferAlgebraND.shape, + shape + ) + this is BufferND && this.strides == this@BufferAlgebraND.strides -> this.buffer + else -> bufferFactory(strides.linearSize) { offset -> get(strides.index(offset)) } + } + + override fun StructureND.map(transform: A.(T) -> T): BufferND { + val buffer = bufferFactory(strides.linearSize) { offset -> + elementContext.transform(buffer[offset]) + } + return BufferND(strides, buffer) } - @PerformancePitfall - override fun StructureND.map(transform: A.(T) -> T): BufferND = mapInline(toBufferND(), transform) + override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): BufferND { + val buffer = bufferFactory(strides.linearSize) { offset -> + elementContext.transform( + strides.index(offset), + buffer[offset] + ) + } + return BufferND(strides, buffer) + } - @PerformancePitfall - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): BufferND = - mapIndexedInline(toBufferND(), transform) - - @PerformancePitfall - override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): BufferND = - zipInline(left.toBufferND(), right.toBufferND(), transform) - - public companion object { - public val defaultIndexerBuilder: (ShapeND) -> ShapeIndexer = ::Strides + override fun combine(a: StructureND, b: StructureND, transform: A.(T, T) -> T): BufferND { + val buffer = bufferFactory(strides.linearSize) { offset -> + elementContext.transform(a.buffer[offset], b.buffer[offset]) + } + return BufferND(strides, buffer) } } -public inline fun > BufferAlgebraND.mapInline( - arg: BufferND, - crossinline transform: A.(T) -> T, -): BufferND { - val indexes = arg.indices - val buffer = arg.buffer - return BufferND( - indexes, - bufferAlgebra.run { - elementBufferFactory(buffer.size) { elementAlgebra.transform(buffer[it]) } - } - ) +public open class BufferedGroupND>( + final override val shape: IntArray, + final override val elementContext: A, + final override val bufferFactory: BufferFactory, +) : GroupND, BufferAlgebraND { + override val strides: Strides = DefaultStrides(shape) + override val zero: BufferND by lazy { produce { zero } } + override fun StructureND.unaryMinus(): StructureND = produce { -get(it) } } -internal inline fun > BufferAlgebraND.mapIndexedInline( - arg: BufferND, - crossinline transform: A.(index: IntArray, arg: T) -> T, -): BufferND { - val indexes = arg.indices - val buffer = arg.buffer - return BufferND( - indexes, - bufferAlgebra.run { - elementBufferFactory(buffer.size) { elementAlgebra.transform(indexes.index(it), buffer[it]) } - } - ) +public open class BufferedRingND>( + shape: IntArray, + elementContext: R, + bufferFactory: BufferFactory, +) : BufferedGroupND(shape, elementContext, bufferFactory), RingND { + override val one: BufferND by lazy { produce { one } } } -internal inline fun > BufferAlgebraND.zipInline( - l: BufferND, - r: BufferND, - crossinline block: A.(l: T, r: T) -> T, -): BufferND { - require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } - val indexes = l.indices - val lbuffer = l.buffer - val rbuffer = r.buffer - return BufferND( - indexes, - bufferAlgebra.run { - elementBufferFactory(lbuffer.size) { elementAlgebra.block(lbuffer[it], rbuffer[it]) } - } - ) -} +public open class BufferedFieldND>( + shape: IntArray, + elementContext: R, + bufferFactory: BufferFactory, +) : BufferedRingND(shape, elementContext, bufferFactory), FieldND { -@OptIn(PerformancePitfall::class) -public open class BufferedGroupNDOps>( - override val bufferAlgebra: BufferAlgebra, - override val indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, -) : GroupOpsND, BufferAlgebraND { - override fun StructureND.unaryMinus(): StructureND = map { -it } -} - -public open class BufferedRingOpsND>( - bufferAlgebra: BufferAlgebra, - indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, -) : BufferedGroupNDOps(bufferAlgebra, indexerBuilder), RingOpsND - -public open class BufferedFieldOpsND>( - bufferAlgebra: BufferAlgebra, - indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, -) : BufferedRingOpsND(bufferAlgebra, indexerBuilder), FieldOpsND { - - public constructor( - elementAlgebra: A, - indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, - ) : this(BufferFieldOps(elementAlgebra), indexerBuilder) - - @OptIn(PerformancePitfall::class) override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } } -public val > BufferAlgebra.nd: BufferedGroupNDOps get() = BufferedGroupNDOps(this) -public val > BufferAlgebra.nd: BufferedRingOpsND get() = BufferedRingOpsND(this) -public val > BufferAlgebra.nd: BufferedFieldOpsND get() = BufferedFieldOpsND(this) - - -public fun > BufferAlgebraND.structureND( +// group factories +public fun > AlgebraND.Companion.group( + space: A, + bufferFactory: BufferFactory, vararg shape: Int, - initializer: A.(IntArray) -> T, -): BufferND = structureND(ShapeND(shape), initializer) +): BufferedGroupND = BufferedGroupND(shape, space, bufferFactory) -public fun , A> A.structureND( - initializer: EA.(IntArray) -> T, -): BufferND where A : BufferAlgebraND, A : WithShape = structureND(shape, initializer) +public inline fun , R> A.ndGroup( + noinline bufferFactory: BufferFactory, + vararg shape: Int, + action: BufferedGroupND.() -> R, +): R { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return AlgebraND.group(this, bufferFactory, *shape).run(action) +} -//// group factories -//public fun > A.ndAlgebra( -// bufferAlgebra: BufferAlgebra, -// vararg shape: Int, -//): BufferedGroupNDOps = BufferedGroupNDOps(bufferAlgebra) -// -//@JvmName("withNdGroup") -//public inline fun , R> A.withNdAlgebra( -// noinline bufferFactory: BufferFactory, -// vararg shape: Int, -// action: BufferedGroupNDOps.() -> R, -//): R { -// contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } -// return ndAlgebra(bufferFactory, *shape).run(action) -//} +//ring factories +public fun > AlgebraND.Companion.ring( + ring: A, + bufferFactory: BufferFactory, + vararg shape: Int, +): BufferedRingND = BufferedRingND(shape, ring, bufferFactory) -////ring factories -//public fun > A.ndAlgebra( -// bufferFactory: BufferFactory, -// vararg shape: Int, -//): BufferedRingNDOps = BufferedRingNDOps(shape, this, bufferFactory) -// -//@JvmName("withNdRing") -//public inline fun , R> A.withNdAlgebra( -// noinline bufferFactory: BufferFactory, -// vararg shape: Int, -// action: BufferedRingNDOps.() -> R, -//): R { -// contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } -// return ndAlgebra(bufferFactory, *shape).run(action) -//} -// -////field factories -//public fun > A.ndAlgebra( -// bufferFactory: BufferFactory, -// vararg shape: Int, -//): BufferedFieldNDOps = BufferedFieldNDOps(shape, this, bufferFactory) -// -///** -// * Create a [FieldND] for this [Field] inferring proper buffer factory from the type -// */ -//@UnstableKMathAPI -//@Suppress("UNCHECKED_CAST") -//public inline fun > A.autoNdAlgebra( -// vararg shape: Int, -//): FieldND = when (this) { -// DoubleField -> DoubleFieldND(shape) as FieldND -// else -> BufferedFieldNDOps(shape, this, Buffer.Companion::auto) -//} -// -//@JvmName("withNdField") -//public inline fun , R> A.withNdAlgebra( -// noinline bufferFactory: BufferFactory, -// vararg shape: Int, -// action: BufferedFieldNDOps.() -> R, -//): R { -// contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } -// return ndAlgebra(bufferFactory, *shape).run(action) -//} \ No newline at end of file +public inline fun , R> A.ndRing( + noinline bufferFactory: BufferFactory, + vararg shape: Int, + action: BufferedRingND.() -> R, +): R { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return AlgebraND.ring(this, bufferFactory, *shape).run(action) +} + +//field factories +public fun > AlgebraND.Companion.field( + field: A, + bufferFactory: BufferFactory, + vararg shape: Int, +): BufferedFieldND = BufferedFieldND(shape, field, bufferFactory) + +@Suppress("UNCHECKED_CAST") +public inline fun > AlgebraND.Companion.auto( + field: A, + vararg shape: Int, +): FieldND = when (field) { + DoubleField -> DoubleFieldND(shape) as FieldND + else -> BufferedFieldND(shape, field, Buffer.Companion::auto) +} + +public inline fun , R> A.ndField( + noinline bufferFactory: BufferFactory, + vararg shape: Int, + action: BufferedFieldND.() -> R, +): R { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return AlgebraND.field(this, bufferFactory, *shape).run(action) +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt index 9217f6fdc..23d961a7e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt @@ -1,109 +1,53 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd -import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableBufferFactory /** * Represents [StructureND] over [Buffer]. * * @param T the type of items. - * @param indices The strides to access elements of [Buffer] by linear indices. + * @param strides The strides to access elements of [Buffer] by linear indices. * @param buffer The underlying buffer. */ -public open class BufferND( - override val indices: ShapeIndexer, - public open val buffer: Buffer, +public class BufferND( + public val strides: Strides, + public val buffer: Buffer, ) : StructureND { - @PerformancePitfall - override operator fun get(index: IntArray): T = buffer[indices.offset(index)] + init { + if (strides.linearSize != buffer.size) { + error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}") + } + } - override val shape: ShapeND get() = indices.shape + override operator fun get(index: IntArray): T = buffer[strides.offset(index)] + + override val shape: IntArray get() = strides.shape + + override fun elements(): Sequence> = strides.indices().map { + it to this[it] + } override fun toString(): String = StructureND.toString(this) } /** - * Create a generic [BufferND] using provided [initializer] + * Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferND] */ -public fun BufferND( - shape: ShapeND, - bufferFactory: BufferFactory = BufferFactory.boxing(), - initializer: (IntArray) -> T, -): BufferND { - val strides = Strides(shape) - return BufferND(strides, bufferFactory(strides.linearSize) { initializer(strides.index(it)) }) -} - -///** -// * Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferND] -// */ -//public inline fun StructureND.mapToBuffer( -// factory: BufferFactory, -// crossinline transform: (T) -> R, -//): BufferND = if (this is BufferND) -// BufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) }) -//else { -// val strides = ColumnStrides(shape) -// BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) -//} -// -///** -// * Transform structure to a new structure using inferred [BufferFactory] -// */ -//public inline fun StructureND.mapToBuffer( -// crossinline transform: (T) -> R, -//): BufferND = mapToBuffer(Buffer.Companion::auto, transform) - -/** - * Represents [MutableStructureND] over [MutableBuffer]. - * - * @param T the type of items. - * @param strides The strides to access elements of [MutableBuffer] by linear indices. - * @param buffer The underlying buffer. - */ -public open class MutableBufferND( - strides: ShapeIndexer, - override val buffer: MutableBuffer, -) : MutableStructureND, BufferND(strides, buffer) { - - @PerformancePitfall - override fun set(index: IntArray, value: T) { - buffer[indices.offset(index)] = value +public inline fun StructureND.mapToBuffer( + factory: BufferFactory = Buffer.Companion::auto, + crossinline transform: (T) -> R, +): BufferND { + return if (this is BufferND) + BufferND(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) }) + else { + val strides = DefaultStrides(shape) + BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) } -} - -/** - * Create a generic [BufferND] using provided [initializer] - */ -public fun MutableBufferND( - shape: ShapeND, - bufferFactory: MutableBufferFactory = MutableBufferFactory.boxing(), - initializer: (IntArray) -> T, -): MutableBufferND { - val strides = Strides(shape) - return MutableBufferND(strides, bufferFactory(strides.linearSize) { initializer(strides.index(it)) }) -} - -///** -// * Transform structure to a new structure using provided [MutableBufferFactory] and optimizing if argument is [MutableBufferND] -// */ -//public inline fun MutableStructureND.mapToMutableBuffer( -// factory: MutableBufferFactory = MutableBufferFactory(MutableBuffer.Companion::auto), -// crossinline transform: (T) -> R, -//): MutableBufferND { -// return if (this is MutableBufferND) -// MutableBufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) }) -// else { -// val strides = ColumnStrides(shape) -// MutableBufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) -// } -//} \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt index 265d1eec8..71532594e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt @@ -1,244 +1,114 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.* +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.structures.DoubleBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract -import kotlin.math.pow -import kotlin.math.pow as kpow - -/** - * A simple mutable [StructureND] of doubles - */ -public class DoubleBufferND( - indexes: ShapeIndexer, - override val buffer: DoubleBuffer, -) : MutableBufferND(indexes, buffer), MutableStructureNDOfDouble{ - override fun getDouble(index: IntArray): Double = buffer[indices.offset(index)] - - override fun setDouble(index: IntArray, value: Double) { - buffer[indices.offset(index)] = value - } -} - - -public sealed class DoubleFieldOpsND : BufferedFieldOpsND(DoubleField.bufferAlgebra), - ScaleOperations>, ExtendedFieldOps> { - - @OptIn(PerformancePitfall::class) - override fun StructureND.toBufferND(): DoubleBufferND = when (this) { - is DoubleBufferND -> this - else -> { - val indexer = indexerBuilder(shape) - DoubleBufferND(indexer, DoubleBuffer(indexer.linearSize) { offset -> get(indexer.index(offset)) }) - } - } - - protected inline fun mapInline( - arg: DoubleBufferND, - transform: (Double) -> Double, - ): DoubleBufferND { - val indexes = arg.indices - val array = arg.buffer.array - return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { transform(array[it]) }) - } - - private inline fun zipInline( - l: DoubleBufferND, - r: DoubleBufferND, - block: (l: Double, r: Double) -> Double, - ): DoubleBufferND { - require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } - val indexes = l.indices - val lArray = l.buffer.array - val rArray = r.buffer.array - return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { block(lArray[it], rArray[it]) }) - } - - @OptIn(PerformancePitfall::class) - override fun StructureND.map(transform: DoubleField.(Double) -> Double): BufferND = - mapInline(toBufferND()) { DoubleField.transform(it) } - - - @OptIn(PerformancePitfall::class) - override fun zip( - left: StructureND, - right: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> DoubleField.transform(l, r) } - - override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND { - val indexer = indexerBuilder(shape) - return DoubleBufferND( - indexer, - DoubleBuffer(indexer.linearSize) { offset -> - elementAlgebra.initializer(indexer.index(offset)) - } - ) - } - - override fun add(left: StructureND, right: StructureND): DoubleBufferND = - zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l + r } - - override fun multiply(left: StructureND, right: StructureND): DoubleBufferND = - zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l * r } - - override fun StructureND.unaryMinus(): DoubleBufferND = mapInline(toBufferND()) { -it } - - override fun StructureND.div(arg: StructureND): DoubleBufferND = - zipInline(toBufferND(), arg.toBufferND()) { l, r -> l / r } - - override fun divide(left: StructureND, right: StructureND): DoubleBufferND = - zipInline(left.toBufferND(), right.toBufferND()) { l: Double, r: Double -> l / r } - - override fun StructureND.div(arg: Double): DoubleBufferND = - mapInline(toBufferND()) { it / arg } - - override fun Double.div(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { this / it } - - override fun StructureND.unaryPlus(): DoubleBufferND = toBufferND() - - override fun StructureND.plus(arg: StructureND): DoubleBufferND = - zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l + r } - - override fun StructureND.minus(arg: StructureND): DoubleBufferND = - zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l - r } - - override fun StructureND.times(arg: StructureND): DoubleBufferND = - zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l * r } - - override fun StructureND.times(k: Number): DoubleBufferND = - mapInline(toBufferND()) { it * k.toDouble() } - - override fun StructureND.div(k: Number): DoubleBufferND = - mapInline(toBufferND()) { it / k.toDouble() } - - override fun Number.times(arg: StructureND): DoubleBufferND = arg * this - - override fun StructureND.plus(arg: Double): DoubleBufferND = mapInline(toBufferND()) { it + arg } - - override fun StructureND.minus(arg: Double): StructureND = mapInline(toBufferND()) { it - arg } - - override fun Double.plus(arg: StructureND): StructureND = arg + this - - override fun Double.minus(arg: StructureND): StructureND = mapInline(arg.toBufferND()) { this - it } - - override fun scale(a: StructureND, value: Double): DoubleBufferND = - mapInline(a.toBufferND()) { it * value } - - override fun exp(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.exp(it) } - - override fun ln(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.ln(it) } - - override fun sin(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.sin(it) } - - override fun cos(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.cos(it) } - - override fun tan(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.tan(it) } - - override fun asin(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.asin(it) } - - override fun acos(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.acos(it) } - - override fun atan(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.atan(it) } - - override fun sinh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.sinh(it) } - - override fun cosh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.cosh(it) } - - override fun tanh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.tanh(it) } - - override fun asinh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.asinh(it) } - - override fun acosh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.acosh(it) } - - override fun atanh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.atanh(it) } - - override fun power( - arg: StructureND, - pow: Number, - ): StructureND = if (pow is Int) { - mapInline(arg.toBufferND()) { it.pow(pow) } - } else { - mapInline(arg.toBufferND()) { it.pow(pow.toDouble()) } - } - - public companion object : DoubleFieldOpsND() -} @OptIn(UnstableKMathAPI::class) -public class DoubleFieldND(override val shape: ShapeND) : - DoubleFieldOpsND(), FieldND, NumbersAddOps>, +public class DoubleFieldND( + shape: IntArray, +) : BufferedFieldND(shape, DoubleField, ::DoubleBuffer), + NumbersAddOperations>, + ScaleOperations>, ExtendedField> { - override fun power(arg: StructureND, pow: UInt): DoubleBufferND = mapInline(arg.toBufferND()) { - it.kpow(pow.toInt()) - } + public override val zero: BufferND by lazy { produce { zero } } + public override val one: BufferND by lazy { produce { one } } - override fun power(arg: StructureND, pow: Int): DoubleBufferND = mapInline(arg.toBufferND()) { - it.kpow(pow) - } - - override fun power(arg: StructureND, pow: Number): DoubleBufferND = if (pow.isInteger()) { - power(arg, pow.toInt()) - } else { - val dpow = pow.toDouble() - mapInline(arg.toBufferND()) { - if (it < 0) throw IllegalArgumentException("Can't raise negative $it to a fractional power") - else it.kpow(dpow) - } - } - - override fun sinh(arg: StructureND): DoubleBufferND = super.sinh(arg) - - override fun cosh(arg: StructureND): DoubleBufferND = super.cosh(arg) - - override fun tanh(arg: StructureND): DoubleBufferND = super.tan(arg) - - override fun asinh(arg: StructureND): DoubleBufferND = super.asinh(arg) - - override fun acosh(arg: StructureND): DoubleBufferND = super.acosh(arg) - - override fun atanh(arg: StructureND): DoubleBufferND = super.atanh(arg) - - override fun number(value: Number): DoubleBufferND { + public override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions - return structureND(shape) { d } + return produce { d } } + + public override val StructureND.buffer: DoubleBuffer + get() = when { + !shape.contentEquals(this@DoubleFieldND.shape) -> throw ShapeMismatchException( + this@DoubleFieldND.shape, + shape + ) + this is BufferND && this.strides == this@DoubleFieldND.strides -> this.buffer as DoubleBuffer + else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } + } + + @Suppress("OVERRIDE_BY_INLINE") + public override inline fun StructureND.map( + transform: DoubleField.(Double) -> Double, + ): BufferND { + val buffer = DoubleBuffer(strides.linearSize) { offset -> DoubleField.transform(buffer.array[offset]) } + return BufferND(strides, buffer) + } + + @Suppress("OVERRIDE_BY_INLINE") + public override inline fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { + val array = DoubleArray(strides.linearSize) { offset -> + val index = strides.index(offset) + DoubleField.initializer(index) + } + return BufferND(strides, DoubleBuffer(array)) + } + + @Suppress("OVERRIDE_BY_INLINE") + public override inline fun StructureND.mapIndexed( + transform: DoubleField.(index: IntArray, Double) -> Double, + ): BufferND = BufferND( + strides, + buffer = DoubleBuffer(strides.linearSize) { offset -> + DoubleField.transform( + strides.index(offset), + buffer.array[offset] + ) + }) + + @Suppress("OVERRIDE_BY_INLINE") + public override inline fun combine( + a: StructureND, + b: StructureND, + transform: DoubleField.(Double, Double) -> Double, + ): BufferND { + val buffer = DoubleBuffer(strides.linearSize) { offset -> + DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset]) + } + return BufferND(strides, buffer) + } + + public override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } + + public override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } + + public override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } + public override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } + + public override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } + public override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } + public override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } + public override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } + public override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } + public override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } + + public override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } + public override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } + public override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } + public override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } + public override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } + public override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } } -public val DoubleField.ndAlgebra: DoubleFieldOpsND get() = DoubleFieldOpsND - -public fun DoubleField.ndAlgebra(vararg shape: Int): DoubleFieldND = DoubleFieldND(ShapeND(shape)) -public fun DoubleField.ndAlgebra(shape: ShapeND): DoubleFieldND = DoubleFieldND(shape) +public fun AlgebraND.Companion.real(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) /** * Produce a context for n-dimensional operations inside this real field */ -@UnstableKMathAPI -public inline fun DoubleField.withNdAlgebra(vararg shape: Int, action: DoubleFieldND.() -> R): R { +public inline fun DoubleField.nd(vararg shape: Int, action: DoubleFieldND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return DoubleFieldND(ShapeND(shape)).run(action) + return DoubleFieldND(shape).run(action) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt deleted file mode 100644 index 1491950d6..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.NumbersAddOps -import space.kscience.kmath.operations.bufferAlgebra -import space.kscience.kmath.structures.IntBuffer -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -public class IntBufferND( - indexes: ShapeIndexer, - override val buffer: IntBuffer, -) : MutableBufferND(indexes, buffer) - -public sealed class IntRingOpsND : BufferedRingOpsND(IntRing.bufferAlgebra) { - - override fun structureND(shape: ShapeND, initializer: IntRing.(IntArray) -> Int): IntBufferND { - val indexer = indexerBuilder(shape) - return IntBufferND( - indexer, - IntBuffer(indexer.linearSize) { offset -> - elementAlgebra.initializer(indexer.index(offset)) - } - ) - } - - public companion object : IntRingOpsND() -} - -@OptIn(UnstableKMathAPI::class) -public class IntRingND( - override val shape: ShapeND -) : IntRingOpsND(), RingND, NumbersAddOps> { - - override fun number(value: Number): BufferND { - val int = value.toInt() // minimize conversions - return structureND(shape) { int } - } -} - -public inline fun IntRing.withNdAlgebra(vararg shape: Int, action: IntRingND.() -> R): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return IntRingND(ShapeND(shape)).run(action) -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt deleted file mode 100644 index 6c35e2f44..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.PerformancePitfall - - -public class PermutedStructureND( - public val origin: StructureND, - public val permutation: (IntArray) -> IntArray, -) : StructureND { - - override val shape: ShapeND - get() = origin.shape - - @OptIn(PerformancePitfall::class) - override fun get(index: IntArray): T { - return origin[permutation(index)] - } -} - -public fun StructureND.permute( - permutation: (IntArray) -> IntArray, -): PermutedStructureND = PermutedStructureND(this, permutation) - -public class PermutedMutableStructureND( - public val origin: MutableStructureND, - override val shape: ShapeND = origin.shape, - public val permutation: (IntArray) -> IntArray, -) : MutableStructureND { - - - @OptIn(PerformancePitfall::class) - override fun set(index: IntArray, value: T) { - origin[permutation(index)] = value - } - - @OptIn(PerformancePitfall::class) - override fun get(index: IntArray): T { - return origin[permutation(index)] - } -} - -public fun MutableStructureND.permute( - newShape: ShapeND = shape, - permutation: (IntArray) -> IntArray, -): PermutedMutableStructureND = PermutedMutableStructureND(this, newShape, permutation) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndices.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndices.kt deleted file mode 100644 index 3a27614c5..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndices.kt +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import kotlin.math.max -import kotlin.native.concurrent.ThreadLocal - -/** - * A converter from linear index to multivariate index - */ -public interface ShapeIndexer : Iterable { - public val shape: ShapeND - - /** - * Get linear index from multidimensional index - */ - public fun offset(index: IntArray): Int - - /** - * Get multidimensional from linear - */ - public fun index(offset: Int): IntArray - - /** - * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides - */ - public val linearSize: Int - - // TODO introduce a fast way to calculate index of the next element? - - /** - * Iterate over ND indices in a natural order - */ - public fun asSequence(): Sequence - - override fun iterator(): Iterator = asSequence().iterator() - - override fun equals(other: Any?): Boolean - override fun hashCode(): Int -} - -/** - * Linear transformation of indexes - */ -public abstract class Strides : ShapeIndexer { - /** - * Array strides - */ - internal abstract val strides: IntArray - - public override fun offset(index: IntArray): Int { - var res = 0 - index.forEachIndexed { i, value -> - if (value !in 0 until shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0, ${this.shape[i]})") - res += value * strides[i] - - } - return res - } - - // TODO introduce a fast way to calculate index of the next element? - - /** - * Iterate over ND indices in a natural order - */ - public override fun asSequence(): Sequence = (0 until linearSize).asSequence().map(::index) - -} - -/** - * Column-first [Strides]. Columns are represented as continuous arrays - */ -public class ColumnStrides(override val shape: ShapeND) : Strides() { - override val linearSize: Int get() = strides[shape.size] - - /** - * Strides for memory access - */ - override val strides: IntArray = sequence { - var current = 1 - yield(1) - - shape.forEach { - current *= it - yield(current) - } - }.toList().toIntArray() - - override fun index(offset: Int): IntArray { - val res = IntArray(shape.size) - var current = offset - var strideIndex = strides.size - 2 - - while (strideIndex >= 0) { - res[strideIndex] = (current / strides[strideIndex]) - current %= strides[strideIndex] - strideIndex-- - } - - return res - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is ColumnStrides) return false - return shape.contentEquals(other.shape) - } - - override fun hashCode(): Int = shape.contentHashCode() - - - public companion object -} - -/** - * This [Strides] implementation follows the last dimension first convention - * For more information: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html - * - * @param shape the shape of the tensor. - */ -public class RowStrides(override val shape: ShapeND) : Strides() { - - override val strides: IntArray = run { - val nDim = shape.size - val res = IntArray(nDim) - if (nDim == 0) return@run res - - var current = nDim - 1 - res[current] = 1 - - while (current > 0) { - res[current - 1] = max(1, shape[current]) * res[current] - current-- - } - res - } - - override fun index(offset: Int): IntArray { - val res = IntArray(shape.size) - var current = offset - var strideIndex = 0 - - while (strideIndex < shape.size) { - res[strideIndex] = (current / strides[strideIndex]) - current %= strides[strideIndex] - strideIndex++ - } - return res - } - - override val linearSize: Int get() = shape.linearSize - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is RowStrides) return false - return shape.contentEquals(other.shape) - } - - override fun hashCode(): Int = shape.contentHashCode() - - public companion object - -} - -@ThreadLocal -private val defaultStridesCache = HashMap() - -/** - * Cached builder for default strides - */ -public fun Strides(shape: ShapeND): Strides = defaultStridesCache.getOrPut(shape) { RowStrides(shape) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt deleted file mode 100644 index d43ebaf1c..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.UnsafeKMathAPI -import kotlin.jvm.JvmInline - -/** - * A read-only ND shape - */ -@JvmInline -public value class ShapeND(@PublishedApi internal val array: IntArray) { - public val size: Int get() = array.size - public operator fun get(index: Int): Int = array[index] - override fun toString(): String = array.contentToString() -} - -public inline fun ShapeND.forEach(block: (value: Int) -> Unit): Unit = array.forEach(block) - -public inline fun ShapeND.forEachIndexed(block: (index: Int, value: Int) -> Unit): Unit = array.forEachIndexed(block) - -public infix fun ShapeND.contentEquals(other: ShapeND): Boolean = array.contentEquals(other.array) - -public fun ShapeND.contentHashCode(): Int = array.contentHashCode() - -public val ShapeND.indices: IntRange get() = array.indices -public val ShapeND.linearSize: Int get() = array.reduce(Int::times) - -public fun ShapeND.slice(range: IntRange): ShapeND = ShapeND(array.sliceArray(range)) - -public fun ShapeND.last(): Int = array.last() - -/** - * A shape including last [n] dimensions of this shape - */ -public fun ShapeND.last(n: Int): ShapeND = ShapeND(array.copyOfRange(size - n, size)) - -public fun ShapeND.first(): Int = array.first() - -/** - * A shape including first [n] dimensions of this shape - */ -public fun ShapeND.first(n: Int): ShapeND = ShapeND(array.copyOfRange(0, n)) - -public operator fun ShapeND.plus(add: IntArray): ShapeND = ShapeND(array + add) - -public operator fun ShapeND.plus(add: ShapeND): ShapeND = ShapeND(array + add.array) - -public fun ShapeND.isEmpty(): Boolean = size == 0 -public fun ShapeND.isNotEmpty(): Boolean = size > 0 - -public fun ShapeND.transposed(i: Int, j: Int): ShapeND = ShapeND(array.copyOf().apply { - val ith = get(i) - val jth = get(j) - set(i, jth) - set(j, ith) -}) - -public operator fun ShapeND.component1(): Int = get(0) -public operator fun ShapeND.component2(): Int = get(1) -public operator fun ShapeND.component3(): Int = get(2) - -/** - * Convert to array with protective copy - */ -public fun ShapeND.toArray(): IntArray = array.copyOf() - -@UnsafeKMathAPI -public fun ShapeND.asArray(): IntArray = array - -public fun ShapeND.asList(): List = array.asList() - - -/** - * An exception is thrown when the expected and actual shape of NDArray differ. - * - * @property expected the expected shape. - * @property actual the actual shape. - */ -public class ShapeMismatchException(public val expected: ShapeND, public val actual: ShapeND) : - RuntimeException("Shape $actual doesn't fit in expected shape ${expected}.") - -public class IndexOutOfShapeException(public val shape: ShapeND, public val index: IntArray) : - RuntimeException("Index ${index.contentToString()} is out of shape ${shape}") - -public fun ShapeND(shapeFirst: Int, vararg shapeRest: Int): ShapeND = ShapeND(intArrayOf(shapeFirst, *shapeRest)) - -public interface WithShape { - public val shape: ShapeND - - public val indices: ShapeIndexer get() = ColumnStrides(shape) -} - -internal fun requireIndexInShape(index: IntArray, shape: ShapeND) { - if (index.size != shape.size) throw IndexOutOfShapeException(shape, index) - shape.forEachIndexed { axis, axisShape -> - if (index[axis] !in 0 until axisShape) throw IndexOutOfShapeException(shape, index) - } -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt index 1b4647146..720a06ace 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt @@ -1,34 +1,41 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.NumbersAddOperations import space.kscience.kmath.operations.ShortRing -import space.kscience.kmath.operations.bufferAlgebra +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.ShortBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract -public sealed class ShortRingOpsND : BufferedRingOpsND(ShortRing.bufferAlgebra) { - public companion object : ShortRingOpsND() -} - @OptIn(UnstableKMathAPI::class) public class ShortRingND( - override val shape: ShapeND -) : ShortRingOpsND(), RingND, NumbersAddOps> { + shape: IntArray, +) : BufferedRingND(shape, ShortRing, Buffer.Companion::auto), + NumbersAddOperations> { + + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } override fun number(value: Number): BufferND { - val short - = value.toShort() // minimize conversions - return structureND(shape) { short } + val d = value.toShort() // minimize conversions + return produce { d } } } -public inline fun ShortRing.withNdAlgebra(vararg shape: Int, action: ShortRingND.() -> R): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return ShortRingND(ShapeND(shape)).run(action) +/** + * Fast element production using function inlining. + */ +public inline fun BufferedRingND.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND { + return BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) } + +public inline fun ShortRing.nd(vararg shape: Int, action: ShortRingND.() -> R): R { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return ShortRingND(shape).run(action) +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt index 984b5ad0f..0f0588fda 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt @@ -1,127 +1,59 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.asMutableBuffer +import space.kscience.kmath.structures.asSequence import kotlin.jvm.JvmInline /** * A structure that is guaranteed to be one-dimensional */ -public interface Structure1D : StructureND, Buffer { - override val dimension: Int get() = 1 +public interface Structure1D : StructureND, Buffer { + public override val dimension: Int get() = 1 - @PerformancePitfall - override operator fun get(index: IntArray): T { + public override operator fun get(index: IntArray): T { require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" } return get(index[0]) } - override operator fun iterator(): Iterator = (0 until size).asSequence().map(::get).iterator() + public override operator fun iterator(): Iterator = (0 until size).asSequence().map(::get).iterator() public companion object } -/** - * A mutable structure that is guaranteed to be one-dimensional - */ -public interface MutableStructure1D : Structure1D, MutableStructureND, MutableBuffer { - - @PerformancePitfall - override operator fun set(index: IntArray, value: T) { - require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" } - set(index[0], value) - } -} - /** * A 1D wrapper for nd-structure */ @JvmInline -private value class Structure1DWrapper(val structure: StructureND) : Structure1D { - override val shape: ShapeND get() = structure.shape +private value class Structure1DWrapper(val structure: StructureND) : Structure1D { + override val shape: IntArray get() = structure.shape override val size: Int get() = structure.shape[0] - @PerformancePitfall override operator fun get(index: Int): T = structure[index] - - @PerformancePitfall override fun elements(): Sequence> = structure.elements() } -/** - * A 1D wrapper for a mutable nd-structure - */ -private class MutableStructure1DWrapper(val structure: MutableStructureND) : MutableStructure1D { - override val shape: ShapeND get() = structure.shape - override val size: Int get() = structure.shape[0] - - @PerformancePitfall - override fun elements(): Sequence> = structure.elements() - - @PerformancePitfall - override fun get(index: Int): T = structure[index] - - @PerformancePitfall - override fun set(index: Int, value: T) { - structure[intArrayOf(index)] = value - } - - @OptIn(PerformancePitfall::class) - override fun copy(): MutableBuffer = structure - .elements() - .map(Pair::second) - .toMutableList() - .asMutableBuffer() - - override fun toString(): String = Buffer.toString(this) -} - /** * A structure wrapper for buffer */ @JvmInline -private value class Buffer1DWrapper(val buffer: Buffer) : Structure1D { - override val shape: ShapeND get() = ShapeND(buffer.size) +private value class Buffer1DWrapper(val buffer: Buffer) : Structure1D { + override val shape: IntArray get() = intArrayOf(buffer.size) override val size: Int get() = buffer.size - @PerformancePitfall - override fun elements(): Sequence> = buffer.asSequence().mapIndexed { index, value -> - intArrayOf(index) to value - } + override fun elements(): Sequence> = + buffer.asSequence().mapIndexed { index, value -> intArrayOf(index) to value } override operator fun get(index: Int): T = buffer[index] } -internal class MutableBuffer1DWrapper(val buffer: MutableBuffer) : MutableStructure1D { - override val shape: ShapeND get() = ShapeND(buffer.size) - override val size: Int get() = buffer.size - - @PerformancePitfall - override fun elements(): Sequence> = buffer.asSequence().mapIndexed { index, value -> - intArrayOf(index) to value - } - - override operator fun get(index: Int): T = buffer[index] - override fun set(index: Int, value: T) { - buffer[index] = value - } - - override fun copy(): MutableBuffer = buffer.copy() - - override fun toString(): String = Buffer.toString(this) -} - /** - * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch. + * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch */ public fun StructureND.as1D(): Structure1D = this as? Structure1D ?: if (shape.size == 1) { when (this) { @@ -130,11 +62,6 @@ public fun StructureND.as1D(): Structure1D = this as? Structure1D ? } } else error("Can't create 1d-structure from ${shape.size}d-structure") -public fun MutableStructureND.as1D(): MutableStructure1D = - this as? MutableStructure1D ?: if (shape.size == 1) { - MutableStructure1DWrapper(this) - } else error("Can't create 1d-structure from ${shape.size}d-structure") - /** * Represent this buffer as 1D structure */ @@ -143,9 +70,8 @@ public fun Buffer.asND(): Structure1D = Buffer1DWrapper(this) /** * Expose inner buffer of this [Structure1D] if possible */ -internal fun Structure1D.asND(): Buffer = when { +internal fun Structure1D.unwrap(): Buffer = when { this is Buffer1DWrapper -> buffer this is Structure1DWrapper && structure is BufferND -> structure.buffer else -> this } - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index e006d09eb..3eee41832 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -1,14 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd -import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableListBuffer import space.kscience.kmath.structures.VirtualBuffer import kotlin.jvm.JvmInline import kotlin.reflect.KClass @@ -18,7 +16,7 @@ import kotlin.reflect.KClass * * @param T the type of items. */ -public interface Structure2D : StructureND { +public interface Structure2D : StructureND { /** * The number of rows in this structure. */ @@ -29,19 +27,17 @@ public interface Structure2D : StructureND { */ public val colNum: Int - override val shape: ShapeND get() = ShapeND(rowNum, colNum) + public override val shape: IntArray get() = intArrayOf(rowNum, colNum) /** * The buffer of rows of this structure. It gets elements from the structure dynamically. */ - @PerformancePitfall public val rows: List> get() = List(rowNum) { i -> VirtualBuffer(colNum) { j -> get(i, j) } } /** * The buffer of columns of this structure. It gets elements from the structure dynamically. */ - @PerformancePitfall public val columns: List> get() = List(colNum) { j -> VirtualBuffer(rowNum) { i -> get(i, j) } } @@ -54,13 +50,11 @@ public interface Structure2D : StructureND { */ public operator fun get(i: Int, j: Int): T - @PerformancePitfall override operator fun get(index: IntArray): T { require(index.size == 2) { "Index dimension mismatch. Expected 2 but found ${index.size}" } return get(index[0], index[1]) } - @PerformancePitfall override fun elements(): Sequence> = sequence { for (i in 0 until rowNum) for (j in 0 until colNum) yield(intArrayOf(i, j) to get(i, j)) @@ -69,111 +63,35 @@ public interface Structure2D : StructureND { public companion object } -/** - * Represents mutable [Structure2D]. - */ -public interface MutableStructure2D : Structure2D, MutableStructureND { - /** - * Inserts an item at the specified indices. - * - * @param i the first index. - * @param j the second index. - * @param value the value. - */ - public operator fun set(i: Int, j: Int, value: T) - - /** - * The buffer of rows of this structure. It gets elements from the structure dynamically. - */ - @PerformancePitfall - override val rows: List> - get() = List(rowNum) { i -> MutableListBuffer(colNum) { j -> get(i, j) } } - - /** - * The buffer of columns of this structure. It gets elements from the structure dynamically. - */ - @PerformancePitfall - override val columns: List> - get() = List(colNum) { j -> MutableListBuffer(rowNum) { i -> get(i, j) } } -} - /** * A 2D wrapper for nd-structure */ @JvmInline -private value class Structure2DWrapper(val structure: StructureND) : Structure2D { - override val shape: ShapeND get() = structure.shape +private value class Structure2DWrapper(val structure: StructureND) : Structure2D { + override val shape: IntArray get() = structure.shape override val rowNum: Int get() = shape[0] override val colNum: Int get() = shape[1] - @PerformancePitfall override operator fun get(i: Int, j: Int): T = structure[i, j] + @UnstableKMathAPI override fun getFeature(type: KClass): F? = structure.getFeature(type) - @PerformancePitfall override fun elements(): Sequence> = structure.elements() } /** - * A 2D wrapper for a mutable nd-structure - */ -private class MutableStructure2DWrapper(val structure: MutableStructureND) : MutableStructure2D { - override val shape: ShapeND get() = structure.shape - - override val rowNum: Int get() = shape[0] - override val colNum: Int get() = shape[1] - - @PerformancePitfall - override operator fun get(i: Int, j: Int): T = structure[i, j] - - @PerformancePitfall - override fun set(index: IntArray, value: T) { - structure[index] = value - } - - @PerformancePitfall - override operator fun set(i: Int, j: Int, value: T) { - structure[intArrayOf(i, j)] = value - } - - @PerformancePitfall - override fun elements(): Sequence> = structure.elements() - - override fun equals(other: Any?): Boolean = false - - override fun hashCode(): Int = 0 - - override fun toString(): String { - return StructureND.toString(structure) - } -} - -/** - * Represents a [StructureND] as [Structure2D]. Throws runtime error in case of dimension mismatch. + * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch */ public fun StructureND.as2D(): Structure2D = this as? Structure2D ?: when (shape.size) { 2 -> Structure2DWrapper(this) else -> error("Can't create 2d-structure from ${shape.size}d-structure") } -/** - * Represents a [StructureND] as [Structure2D]. Throws runtime error in case of dimension mismatch. - */ -public fun MutableStructureND.as2D(): MutableStructure2D = - this as? MutableStructure2D ?: when (shape.size) { - 2 -> MutableStructure2DWrapper(this) - else -> error("Can't create 2d-structure from ${shape.size}d-structure") - } - /** * Expose inner [StructureND] if possible */ -internal fun Structure2D.asND(): StructureND = +internal fun Structure2D.unwrap(): StructureND = if (this is Structure2DWrapper) structure - else this - -internal fun MutableStructure2D.asND(): MutableStructureND = - if (this is MutableStructure2DWrapper) structure else this - + else this \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index e643186ba..0656b1f7f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -1,26 +1,21 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.misc.Feature -import space.kscience.kmath.misc.Featured -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import kotlin.jvm.JvmName -import kotlin.math.abs +import kotlin.native.concurrent.ThreadLocal import kotlin.reflect.KClass -public interface StructureFeature : Feature +public interface StructureFeature /** - * Represents n-dimensional structure i.e., multidimensional container of items of the same type and size. The number + * Represents n-dimensional structure, i.e. multidimensional container of items of the same type and size. The number * of dimensions and items in an array is defined by its shape, which is a sequence of non-negative integers that * specify the sizes of each dimension. * @@ -28,12 +23,12 @@ public interface StructureFeature : Feature * * @param T the type of items. */ -public interface StructureND : Featured, WithShape { +public interface StructureND { /** - * The shape of structure i.e., non-empty sequence of non-negative integers that specify sizes of dimensions of + * The shape of structure, i.e. non-empty sequence of non-negative integers that specify sizes of dimensions of * this structure. */ - override val shape: ShapeND + public val shape: IntArray /** * The count of dimensions in this structure. It should be equal to size of [shape]. @@ -46,7 +41,6 @@ public interface StructureND : Featured, WithShape { * @param index the indices. * @return the value. */ - @PerformancePitfall public operator fun get(index: IntArray): T /** @@ -54,71 +48,47 @@ public interface StructureND : Featured, WithShape { * * @return the lazy sequence of pairs of indices to values. */ - @PerformancePitfall - public fun elements(): Sequence> = indices.asSequence().map { it to get(it) } + public fun elements(): Sequence> /** - * Feature is some additional structure information that allows to access it special properties or hints. - * If the feature is not present, `null` is returned. + * Feature is some additional strucure information which allows to access it special properties or hints. + * If the feature is not present, null is returned. */ - override fun getFeature(type: KClass): F? = null + @UnstableKMathAPI + public fun getFeature(type: KClass): F? = null public companion object { /** * Indicates whether some [StructureND] is equal to another one. */ - @PerformancePitfall public fun contentEquals(st1: StructureND, st2: StructureND): Boolean { if (st1 === st2) return true // fast comparison of buffers if possible - if (st1 is BufferND && st2 is BufferND && st1.indices == st2.indices) + if (st1 is BufferND && st2 is BufferND && st1.strides == st2.strides) return Buffer.contentEquals(st1.buffer, st2.buffer) //element by element comparison if it could not be avoided return st1.elements().all { (index, value) -> value == st2[index] } } - @PerformancePitfall - public fun contentEquals( - st1: StructureND, - st2: StructureND, - tolerance: Double = 1e-11, - ): Boolean { - if (st1 === st2) return true - - // fast comparison of buffers if possible - if (st1 is BufferND && st2 is BufferND && st1.indices == st2.indices) - return Buffer.contentEquals(st1.buffer, st2.buffer) - - //element by element comparison if it could not be avoided - return st1.elements().all { (index, value) -> abs(value - st2[index]) < tolerance } - } - /** * Debug output to string */ - @OptIn(PerformancePitfall::class) public fun toString(structure: StructureND<*>): String { val bufferRepr: String = when (structure.shape.size) { 1 -> (0 until structure.shape[0]).map { structure[it] } .joinToString(prefix = "[", postfix = "]", separator = ", ") - - 2 -> (0 until structure.shape[0]).joinToString( - prefix = "[\n", - postfix = "\n]", - separator = ",\n" - ) { i -> - (0 until structure.shape[1]).joinToString(prefix = " [", postfix = "]", separator = ", ") { j -> + 2 -> (0 until structure.shape[0]).joinToString(prefix = "[", postfix = "]", separator = ", ") { i -> + (0 until structure.shape[1]).joinToString(prefix = "[", postfix = "]", separator = ", ") { j -> structure[i, j].toString() } } - else -> "..." } val className = structure::class.simpleName ?: "StructureND" - return "$className(shape=${structure.shape}, buffer=$bufferRepr)" + return "$className(shape=${structure.shape.contentToString()}, buffer=$bufferRepr)" } /** @@ -128,7 +98,7 @@ public interface StructureND : Featured, WithShape { */ public fun buffered( strides: Strides, - bufferFactory: BufferFactory = BufferFactory.boxing(), + bufferFactory: BufferFactory = Buffer.Companion::boxing, initializer: (IntArray) -> T, ): BufferND = BufferND(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) }) @@ -147,84 +117,41 @@ public interface StructureND : Featured, WithShape { ): BufferND = BufferND(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) }) public fun buffered( - shape: ShapeND, - bufferFactory: BufferFactory = BufferFactory.boxing(), + shape: IntArray, + bufferFactory: BufferFactory = Buffer.Companion::boxing, initializer: (IntArray) -> T, - ): BufferND = buffered(ColumnStrides(shape), bufferFactory, initializer) + ): BufferND = buffered(DefaultStrides(shape), bufferFactory, initializer) public inline fun auto( - shape: ShapeND, + shape: IntArray, crossinline initializer: (IntArray) -> T, - ): BufferND = auto(ColumnStrides(shape), initializer) + ): BufferND = auto(DefaultStrides(shape), initializer) @JvmName("autoVarArg") public inline fun auto( vararg shape: Int, crossinline initializer: (IntArray) -> T, ): BufferND = - auto(ColumnStrides(ShapeND(shape)), initializer) + auto(DefaultStrides(shape), initializer) public inline fun auto( type: KClass, vararg shape: Int, crossinline initializer: (IntArray) -> T, - ): BufferND = auto(type, ColumnStrides(ShapeND(shape)), initializer) + ): BufferND = auto(type, DefaultStrides(shape), initializer) } } -/** - * Indicates whether some [StructureND] is equal to another one. - */ -@PerformancePitfall -public fun > AlgebraND>.contentEquals( - st1: StructureND, - st2: StructureND, -): Boolean = StructureND.contentEquals(st1, st2) - -/** - * Indicates whether some [StructureND] is equal to another one. - */ -@PerformancePitfall -public fun > LinearSpace>.contentEquals( - st1: StructureND, - st2: StructureND, -): Boolean = StructureND.contentEquals(st1, st2) - -/** - * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. - */ -@PerformancePitfall -public fun > GroupOpsND>.contentEquals( - st1: StructureND, - st2: StructureND, - absoluteTolerance: T, -): Boolean = st1.elements().all { (index, value) -> elementAlgebra { (value - st2[index]) } < absoluteTolerance } - -/** - * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. - */ -@PerformancePitfall -public fun > LinearSpace>.contentEquals( - st1: StructureND, - st2: StructureND, - absoluteTolerance: T, -): Boolean = st1.elements().all { (index, value) -> elementAlgebra { (value - st2[index]) } < absoluteTolerance } - /** * Returns the value at the specified indices. * * @param index the indices. * @return the value. */ -@PerformancePitfall public operator fun StructureND.get(vararg index: Int): T = get(index) -public operator fun StructureND.get(vararg index: Int): Double = getDouble(index) - -public operator fun StructureND.get(vararg index: Int): Int = getInt(index) - -//@UnstableKMathAPI -//public inline fun StructureND<*>.getFeature(): T? = getFeature(T::class) +@UnstableKMathAPI +public inline fun StructureND<*>.getFeature(): T? = getFeature(T::class) /** * Represents mutable [StructureND]. @@ -236,14 +163,120 @@ public interface MutableStructureND : StructureND { * @param index the indices. * @param value the value. */ - @PerformancePitfall public operator fun set(index: IntArray, value: T) } /** - * Set value at specified indices + * Transform a structure element-by element in place. */ -@PerformancePitfall -public operator fun MutableStructureND.set(vararg index: Int, value: T) { - set(index, value) -} \ No newline at end of file +public inline fun MutableStructureND.mapInPlace(action: (IntArray, T) -> T): Unit = + elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } + +/** + * A way to convert ND index to linear one and back. + */ +public interface Strides { + /** + * Shape of NDStructure + */ + public val shape: IntArray + + /** + * Array strides + */ + public val strides: List + + /** + * Get linear index from multidimensional index + */ + public fun offset(index: IntArray): Int + + /** + * Get multidimensional from linear + */ + public fun index(offset: Int): IntArray + + /** + * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides + */ + public val linearSize: Int + + // TODO introduce a fast way to calculate index of the next element? + + /** + * Iterate over ND indices in a natural order + */ + public fun indices(): Sequence = (0 until linearSize).asSequence().map { + index(it) + } +} + +/** + * Simple implementation of [Strides]. + */ +public class DefaultStrides private constructor(override val shape: IntArray) : Strides { + override val linearSize: Int + get() = strides[shape.size] + + /** + * Strides for memory access + */ + override val strides: List by lazy { + sequence { + var current = 1 + yield(1) + + shape.forEach { + current *= it + yield(current) + } + }.toList() + } + + override fun offset(index: IntArray): Int = index.mapIndexed { i, value -> + if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${this.shape[i]})") + value * strides[i] + }.sum() + + override fun index(offset: Int): IntArray { + val res = IntArray(shape.size) + var current = offset + var strideIndex = strides.size - 2 + + while (strideIndex >= 0) { + res[strideIndex] = (current / strides[strideIndex]) + current %= strides[strideIndex] + strideIndex-- + } + + return res + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is DefaultStrides) return false + if (!shape.contentEquals(other.shape)) return false + return true + } + + override fun hashCode(): Int = shape.contentHashCode() + + @ThreadLocal + public companion object { + private val defaultStridesCache = HashMap() + + /** + * Cached builder for default strides + */ + public operator fun invoke(shape: IntArray): Strides = + defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } + } +} + +public inline fun StructureND.combine( + struct: StructureND, + crossinline block: (T, T) -> T, +): StructureND { + require(shape.contentEquals(struct.shape)) { "Shape mismatch in structure combination" } + return StructureND.auto(shape) { block(this[it], struct[it]) } +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt deleted file mode 100644 index 606b9a631..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI - -public open class VirtualStructureND( - override val shape: ShapeND, - public val producer: (IntArray) -> T, -) : StructureND { - - @PerformancePitfall - override fun get(index: IntArray): T { - requireIndexInShape(index, shape) - return producer(index) - } -} - -@UnstableKMathAPI -public class VirtualDoubleStructureND( - shape: ShapeND, - producer: (IntArray) -> Double, -) : VirtualStructureND(shape, producer) - -@UnstableKMathAPI -public class VirtualIntStructureND( - shape: ShapeND, - producer: (IntArray) -> Int, -) : VirtualStructureND(shape, producer) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt deleted file mode 100644 index f0d4bd7f5..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.Ring -import kotlin.jvm.JvmName - - -public fun > AlgebraND.structureND( - shapeFirst: Int, - vararg shapeRest: Int, - initializer: A.(IntArray) -> T -): StructureND = structureND(ShapeND(shapeFirst, *shapeRest), initializer) - -public fun > AlgebraND.zero(shape: ShapeND): StructureND = structureND(shape) { zero } - -@JvmName("zeroVarArg") -public fun > AlgebraND.zero( - shapeFirst: Int, - vararg shapeRest: Int, -): StructureND = structureND(shapeFirst, *shapeRest) { zero } - -public fun > AlgebraND.one(shape: ShapeND): StructureND = structureND(shape) { one } - -@JvmName("oneVarArg") -public fun > AlgebraND.one( - shapeFirst: Int, - vararg shapeRest: Int, -): StructureND = structureND(shapeFirst, *shapeRest) { one } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt deleted file mode 100644 index 40db5187f..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.PerformancePitfall - -@OptIn(PerformancePitfall::class) -public fun StructureND.roll(axis: Int, step: Int = 1): StructureND { - require(axis in shape.indices) { "Axis $axis is outside of shape dimensions: [0, ${shape.size})" } - return VirtualStructureND(shape) { index -> - val newIndex: IntArray = IntArray(index.size) { indexAxis -> - if (indexAxis == axis) { - (index[indexAxis] + step).mod(shape[indexAxis]) - } else { - index[indexAxis] - } - } - get(newIndex) - } -} - -@OptIn(PerformancePitfall::class) -public fun StructureND.roll(pair: Pair, vararg others: Pair): StructureND { - val axisMap: Map = mapOf(pair, *others) - require(axisMap.keys.all { it in shape.indices }) { "Some of axes ${axisMap.keys} is outside of shape dimensions: [0, ${shape.size})" } - return VirtualStructureND(shape) { index -> - val newIndex: IntArray = IntArray(index.size) { indexAxis -> - val offset = axisMap[indexAxis] ?: 0 - (index[indexAxis] + offset).mod(shape[indexAxis]) - } - get(newIndex) - } -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt deleted file mode 100644 index 28e32363f..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.PerformancePitfall - -public interface StructureNDOfDouble : StructureND { - /** - * Guaranteed non-blocking access to content - */ - public fun getDouble(index: IntArray): Double -} - -/** - * Optimized method to access primitive without boxing if possible - */ -@OptIn(PerformancePitfall::class) -public fun StructureND.getDouble(index: IntArray): Double = - if (this is StructureNDOfDouble) getDouble(index) else get(index) - -public interface MutableStructureNDOfDouble : StructureNDOfDouble, MutableStructureND { - /** - * Guaranteed non-blocking access to content - */ - public fun setDouble(index: IntArray, value: Double) -} - -@OptIn(PerformancePitfall::class) -public fun MutableStructureND.getDouble(index: IntArray): Double = - if (this is StructureNDOfDouble) getDouble(index) else get(index) - - -public interface StructureNDOfInt : StructureND { - /** - * Guaranteed non-blocking access to content - */ - public fun getInt(index: IntArray): Int -} - -@OptIn(PerformancePitfall::class) -public fun StructureND.getInt(index: IntArray): Int = - if (this is StructureNDOfInt) getInt(index) else get(index) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt index 0960ab023..0334e0466 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt @@ -1,14 +1,17 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.operations -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Ring.Companion.optimizedPower -import space.kscience.kmath.structures.MutableBufferFactory +import space.kscience.kmath.misc.Symbol + +/** + * Stub for DSL the [Algebra] is. + */ +@DslMarker +public annotation class KMathContext /** * Represents an algebraic structure. @@ -16,23 +19,19 @@ import space.kscience.kmath.structures.MutableBufferFactory * @param T the type of element of this structure. */ public interface Algebra { - - /** - * Provide a factory for buffers, associated with this [Algebra] - */ - public val bufferFactory: MutableBufferFactory get() = MutableBufferFactory.boxing() - /** * Wraps a raw string to [T] object. This method is designed for three purposes: * * 1. Mathematical constants (`e`, `pi`). - * 1. Variables for expression-like contexts (`a`, `b`, `c`…). - * 1. Literals (`{1, 2}`, (`(3; 4)`)). + * 2. Variables for expression-like contexts (`a`, `b`, `c`...). + * 3. Literals (`{1, 2}`, (`(3; 4)`)). * - * If algebra can't parse the string, then this method must throw [kotlin.IllegalStateException]. + * In case if algebra can't parse the string, this method must throw [kotlin.IllegalStateException]. + * + * Returns `null` if symbol could not be bound to the context * * @param value the raw string. - * @return an object or `null` if symbol could not be bound to the context. + * @return an object. */ public fun bindSymbolOrNull(value: String): T? = null @@ -43,12 +42,13 @@ public interface Algebra { bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this") /** - * Dynamically dispatches a unary operation with the certain name. + * Dynamically dispatches an unary operation with the certain name. * - * Implementations must fulfil the following requirements: + * This function must follow two properties: * - * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. - * 1. Equivalence to [unaryOperation]: for any `a` and `b`, `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second `unaryOperation` overload: + * i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. * * @param operation the name of operation. * @return an operation. @@ -57,13 +57,13 @@ public interface Algebra { error("Unary operation $operation not defined in $this") /** - * Dynamically invokes a unary operation with the certain name. + * Dynamically invokes an unary operation with the certain name. * - * Implementations must fulfil the following requirements: + * This function must follow two properties: * - * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. - * 1. Equivalence to [unaryOperationFunction]: i.e., for any `a` and `b`, - * `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second [unaryOperationFunction] overload: + * i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. * * @param operation the name of operation. * @param arg the argument of operation. @@ -74,26 +74,26 @@ public interface Algebra { /** * Dynamically dispatches a binary operation with the certain name. * - * Implementations must fulfil the following requirements: + * This function must follow two properties: * - * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. - * 1. Equivalence to [binaryOperation]: for any `a`, `b`, and `c`, - * `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second [binaryOperationFunction] overload: + * i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * * @param operation the name of operation. * @return an operation. */ public fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = - error("Binary operation '$operation' not defined in $this") + error("Binary operation $operation not defined in $this") /** * Dynamically invokes a binary operation with the certain name. * - * Implementations must fulfil the following requirements: + * This function must follow two properties: * - * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. - * 1. Equivalence to [binaryOperationFunction]: for any `a`, `b`, and `c`, - * `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second [binaryOperationFunction] overload: + * i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -102,14 +102,6 @@ public interface Algebra { */ public fun binaryOperation(operation: String, left: T, right: T): T = binaryOperationFunction(operation)(left, right) - - /** - * Export an algebra element, so it could be accessed even after algebra scope is closed. - * This method must be used on algebras where data is stored externally or any local algebra state is used. - * By default (if not overridden), exports the object itself. - */ - @UnstableKMathAPI - public fun export(arg: T): T = arg } public fun Algebra.bindSymbolOrNull(symbol: Symbol): T? = bindSymbolOrNull(symbol.identity) @@ -123,22 +115,22 @@ public fun Algebra.bindSymbol(symbol: Symbol): T = bindSymbol(symbol.iden public inline operator fun , R> A.invoke(block: A.() -> R): R = run(block) /** - * Represents group without neutral element (also known as inverse semigroup) i.e., algebraic structure with + * Represents group without neutral element (also known as inverse semigroup), i.e. algebraic structure with * associative, binary operation [add]. * * @param T the type of element of this semispace. */ -public interface GroupOps : Algebra { +public interface GroupOperations : Algebra { /** * Addition of two elements. * - * @param left the augend. - * @param right the addend. + * @param a the augend. + * @param b the addend. * @return the sum. */ - public fun add(left: T, right: T): T + public fun add(a: T, b: T): T - // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176. + // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176 /** * The negation of this element. @@ -160,28 +152,27 @@ public interface GroupOps : Algebra { * Addition of two elements. * * @receiver the augend. - * @param arg the addend. + * @param b the addend. * @return the sum. */ - public operator fun T.plus(arg: T): T = add(this, arg) + public operator fun T.plus(b: T): T = add(this, b) /** * Subtraction of two elements. * * @receiver the minuend. - * @param arg the subtrahend. + * @param b the subtrahend. * @return the difference. */ - public operator fun T.minus(arg: T): T = add(this, -arg) + public operator fun T.minus(b: T): T = add(this, -b) - // Dynamic dispatch of operations - override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { + public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> +arg } MINUS_OPERATION -> { arg -> -arg } else -> super.unaryOperationFunction(operation) } - override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { + public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { PLUS_OPERATION -> ::add MINUS_OPERATION -> { left, right -> left - right } else -> super.binaryOperationFunction(operation) @@ -201,11 +192,11 @@ public interface GroupOps : Algebra { } /** - * Represents group i.e., algebraic structure with associative, binary operation [add]. + * Represents group, i.e. algebraic structure with associative, binary operation [add]. * * @param T the type of element of this semispace. */ -public interface Group : GroupOps { +public interface Group : GroupOperations { /** * The neutral element of addition. */ @@ -213,29 +204,29 @@ public interface Group : GroupOps { } /** - * Represents ring without multiplicative and additive identities i.e., algebraic structure with + * Represents ring without multiplicative and additive identities, i.e. algebraic structure with * associative, binary, commutative operation [add] and associative, operation [multiply] distributive over [add]. * * @param T the type of element of this semiring. */ -public interface RingOps : GroupOps { +public interface RingOperations : GroupOperations { /** * Multiplies two elements. * - * @param left the multiplier. - * @param right the multiplicand. + * @param a the multiplier. + * @param b the multiplicand. */ - public fun multiply(left: T, right: T): T + public fun multiply(a: T, b: T): T /** * Multiplies this element by scalar. * * @receiver the multiplier. - * @param arg the multiplicand. + * @param b the multiplicand. */ - public operator fun T.times(arg: T): T = multiply(this, arg) + public operator fun T.times(b: T): T = multiply(this, b) - override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { + public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { TIMES_OPERATION -> ::multiply else -> super.binaryOperationFunction(operation) } @@ -249,79 +240,44 @@ public interface RingOps : GroupOps { } /** - * Represents ring i.e., algebraic structure with two associative binary operations called "addition" and + * Represents ring, i.e. algebraic structure with two associative binary operations called "addition" and * "multiplication" and their neutral elements. * * @param T the type of element of this ring. */ -public interface Ring : Group, RingOps { +public interface Ring : Group, RingOperations { /** - * The neutral element of multiplication + * neutral operation for multiplication */ public val one: T - - /** - * Raises [arg] to the integer power [pow]. - */ - public fun power(arg: T, pow: UInt): T = optimizedPower(arg, pow) - - public companion object{ - /** - * Raises [arg] to the non-negative integer power [exponent]. - * - * Special case: 0 ^ 0 is 1. - * - * @receiver the algebra to provide multiplication. - * @param arg the base. - * @param exponent the exponent. - * @return the base raised to the power. - * @author Evgeniy Zhelenskiy - */ - internal fun Ring.optimizedPower(arg: T, exponent: UInt): T = when { - arg == zero && exponent > 0U -> zero - arg == one -> arg - arg == -one -> powWithoutOptimization(arg, exponent % 2U) - else -> powWithoutOptimization(arg, exponent) - } - - private fun Ring.powWithoutOptimization(base: T, exponent: UInt): T = when (exponent) { - 0U -> one - 1U -> base - else -> { - val pre = powWithoutOptimization(base, exponent shr 1).let { it * it } - if (exponent and 1U == 0U) pre else pre * base - } - } - } } /** - * Represents field without multiplicative and additive identities i.e., algebraic structure with associative, binary, - * commutative operations [add] and [multiply]; binary operation [divide] as multiplication of left operand by - * reciprocal of right one. + * Represents field without without multiplicative and additive identities, i.e. algebraic structure with associative, binary, commutative operations + * [add] and [multiply]; binary operation [divide] as multiplication of left operand by reciprocal of right one. * * @param T the type of element of this semifield. */ -public interface FieldOps : RingOps { +public interface FieldOperations : RingOperations { /** * Division of two elements. * - * @param left the dividend. - * @param right the divisor. + * @param a the dividend. + * @param b the divisor. * @return the quotient. */ - public fun divide(left: T, right: T): T + public fun divide(a: T, b: T): T /** * Division of two elements. * * @receiver the dividend. - * @param arg the divisor. + * @param b the divisor. * @return the quotient. */ - public operator fun T.div(arg: T): T = divide(this, arg) + public operator fun T.div(b: T): T = divide(this, b) - override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { + public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { DIV_OPERATION -> ::divide else -> super.binaryOperationFunction(operation) } @@ -335,32 +291,12 @@ public interface FieldOps : RingOps { } /** - * Represents field i.e., algebraic structure with three operations: associative, commutative addition and + * Represents field, i.e. algebraic structure with three operations: associative, commutative addition and * multiplication, and division. **This interface differs from the eponymous mathematical definition: fields in KMath * also support associative multiplication by scalar.** * * @param T the type of element of this field. */ -public interface Field : Ring, FieldOps, ScaleOperations, NumericAlgebra { - override fun number(value: Number): T = scale(one, value.toDouble()) - - public fun power(arg: T, pow: Int): T = optimizedPower(arg, pow) - - public companion object{ - /** - * Raises [arg] to the integer power [exponent]. - * - * Special case: 0 ^ 0 is 1. - * - * @receiver the algebra to provide multiplication and division. - * @param arg the base. - * @param exponent the exponent. - * @return the base raised to the power. - * @author Iaroslav Postovalov, Evgeniy Zhelenskiy - */ - private fun Field.optimizedPower(arg: T, exponent: Int): T = when { - exponent < 0 -> one / (this as Ring).optimizedPower(arg, if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt()) - else -> (this as Ring).optimizedPower(arg, exponent.toUInt()) - } - } +public interface Field : Ring, FieldOperations, ScaleOperations, NumericAlgebra { + public override fun number(value: Number): T = scale(one, value.toDouble()) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt new file mode 100644 index 000000000..d7c87f213 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt @@ -0,0 +1,116 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.operations + +import space.kscience.kmath.misc.UnstableKMathAPI + +/** + * The generic mathematics elements which is able to store its context + * + * @param C the type of mathematical context for this element. + * @param T the type wrapped by this wrapper. + */ +public interface AlgebraElement> { + /** + * The context this element belongs to. + */ + public val context: C +} +// +///** +// * Divides this element by number. +// * +// * @param k the divisor. +// * @return the quotient. +// */ +//public operator fun , S : Space> T.div(k: Number): T = +// context.multiply(this, 1.0 / k.toDouble()) +// +///** +// * Multiplies this element by number. +// * +// * @param k the multiplicand. +// * @return the product. +// */ +//public operator fun , S : Space> T.times(k: Number): T = +// context.multiply(this, k.toDouble()) + +/** + * Subtracts element from this one. + * + * @param b the subtrahend. + * @return the difference. + */ +@UnstableKMathAPI +public operator fun , S : NumbersAddOperations> T.minus(b: T): T = + context.add(this, context.run { -b }) + +/** + * Adds element to this one. + * + * @receiver the augend. + * @param b the addend. + * @return the sum. + */ +public operator fun , S : Ring> T.plus(b: T): T = + context.add(this, b) + +///** +// * Number times element +// */ +//public operator fun , S : Space> Number.times(element: T): T = +// element.times(this) + +/** + * Multiplies this element by another one. + * + * @receiver the multiplicand. + * @param b the multiplier. + * @return the product. + */ +public operator fun , R : Ring> T.times(b: T): T = + context.multiply(this, b) + + +/** + * Divides this element by another one. + * + * @param b the divisor. + * @return the quotient. + */ +public operator fun , F : Field> T.div(b: T): T = + context.divide(this, b) + + +/** + * The element of [Group]. + * + * @param T the type of space operation results. + * @param I self type of the element. Needed for static type checking. + * @param S the type of space. + */ +@UnstableKMathAPI +public interface GroupElement, S : Group> : AlgebraElement + +/** + * The element of [Ring]. + * + * @param T the type of ring operation results. + * @param I self type of the element. Needed for static type checking. + * @param R the type of ring. + */ +@UnstableKMathAPI +public interface RingElement, R : Ring> : GroupElement + +/** + * The element of [Field]. + * + * @param T the type of field operation results. + * @param I self type of the element. Needed for static type checking. + * @param F the type of field. + */ +@UnstableKMathAPI +public interface FieldElement, F : Field> : RingElement \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt index 34a6d4a80..e74efa9ca 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt @@ -1,15 +1,17 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.operations -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.BufferedRingOpsND +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.AlgebraND +import space.kscience.kmath.nd.BufferedRingND import space.kscience.kmath.operations.BigInt.Companion.BASE import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.MutableBuffer import kotlin.math.log2 import kotlin.math.max import kotlin.math.min @@ -25,7 +27,7 @@ private typealias TBase = ULong * @author Peter Klimai */ @OptIn(UnstableKMathAPI::class) -public object BigIntField : Field, NumbersAddOps, ScaleOperations { +public object BigIntField : Field, NumbersAddOperations, ScaleOperations { override val zero: BigInt = BigInt.ZERO override val one: BigInt = BigInt.ONE @@ -33,10 +35,10 @@ public object BigIntField : Field, NumbersAddOps, ScaleOperation @Suppress("EXTENSION_SHADOWED_BY_MEMBER") override fun BigInt.unaryMinus(): BigInt = -this - override fun add(left: BigInt, right: BigInt): BigInt = left.plus(right) + override fun add(a: BigInt, b: BigInt): BigInt = a.plus(b) override fun scale(a: BigInt, value: Double): BigInt = a.times(number(value)) - override fun multiply(left: BigInt, right: BigInt): BigInt = left.times(right) - override fun divide(left: BigInt, right: BigInt): BigInt = left.div(right) + override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b) + override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b) public operator fun String.unaryPlus(): BigInt = this.parseBigInteger() ?: error("Can't parse $this as big integer") public operator fun String.unaryMinus(): BigInt = @@ -47,16 +49,17 @@ public class BigInt internal constructor( private val sign: Byte, private val magnitude: Magnitude, ) : Comparable { - override fun compareTo(other: BigInt): Int = when { + public override fun compareTo(other: BigInt): Int = when { (sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0 sign < other.sign -> -1 sign > other.sign -> 1 else -> sign * compareMagnitudes(magnitude, other.magnitude) } - override fun equals(other: Any?): Boolean = other is BigInt && compareTo(other) == 0 + public override fun equals(other: Any?): Boolean = + if (other is BigInt) compareTo(other) == 0 else error("Can't compare KBigInteger to a different type") - override fun hashCode(): Int = magnitude.hashCode() + sign + public override fun hashCode(): Int = magnitude.hashCode() + sign public fun abs(): BigInt = if (sign == 0.toByte()) this else BigInt(1, magnitude) @@ -84,25 +87,20 @@ public class BigInt internal constructor( public operator fun times(b: BigInt): BigInt = when { this.sign == 0.toByte() -> ZERO b.sign == 0.toByte() -> ZERO - b.magnitude.size == 1 -> this * b.magnitude[0] * b.sign.toInt() - this.magnitude.size == 1 -> b * this.magnitude[0] * this.sign.toInt() +// TODO: Karatsuba else -> BigInt((this.sign * b.sign).toByte(), multiplyMagnitudes(this.magnitude, b.magnitude)) } public operator fun times(other: UInt): BigInt = when { sign == 0.toByte() -> ZERO other == 0U -> ZERO - other == 1U -> this else -> BigInt(sign, multiplyMagnitudeByUInt(magnitude, other)) } - public fun pow(exponent: UInt): BigInt = BigIntField.power(this, exponent) - - public operator fun times(other: Int): BigInt = when { - other > 0 -> this * kotlin.math.abs(other).toUInt() - other != Int.MIN_VALUE -> -this * kotlin.math.abs(other).toUInt() - else -> times(other.toBigInt()) - } + public operator fun times(other: Int): BigInt = if (other > 0) + this * kotlin.math.abs(other).toUInt() + else + -this * kotlin.math.abs(other).toUInt() public operator fun div(other: UInt): BigInt = BigInt(this.sign, divideMagnitudeByUInt(this.magnitude, other)) @@ -119,7 +117,7 @@ public class BigInt internal constructor( var r = ZERO val bitSize = - (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: (0f + 1))).toInt() + (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: 0f + 1)).toInt() for (i in bitSize downTo 0) { r = r shl 1 @@ -240,7 +238,6 @@ public class BigInt internal constructor( public const val BASE_SIZE: Int = 32 public val ZERO: BigInt = BigInt(0, uintArrayOf()) public val ONE: BigInt = BigInt(1, uintArrayOf(1u)) - private const val KARATSUBA_THRESHOLD = 80 private val hexMapping: HashMap = hashMapOf( 0U to "0", 1U to "1", 2U to "2", 3U to "3", @@ -279,7 +276,7 @@ public class BigInt internal constructor( } result[i] = (res and BASE).toUInt() - carry = res shr BASE_SIZE + carry = (res shr BASE_SIZE) } result[resultLength - 1] = carry.toUInt() @@ -321,14 +318,7 @@ public class BigInt internal constructor( return stripLeadingZeros(result) } - internal fun multiplyMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude = when { - mag1.size + mag2.size < KARATSUBA_THRESHOLD || mag1.isEmpty() || mag2.isEmpty() -> - naiveMultiplyMagnitudes(mag1, mag2) - // TODO implement Fourier - else -> karatsubaMultiplyMagnitudes(mag1, mag2) - } - - internal fun naiveMultiplyMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { + private fun multiplyMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { val resultLength = mag1.size + mag2.size val result = Magnitude(resultLength) @@ -347,21 +337,6 @@ public class BigInt internal constructor( return stripLeadingZeros(result) } - internal fun karatsubaMultiplyMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { - //https://en.wikipedia.org/wiki/Karatsuba_algorithm - val halfSize = min(mag1.size, mag2.size) / 2 - val x0 = mag1.sliceArray(0 until halfSize).toBigInt(1) - val x1 = mag1.sliceArray(halfSize until mag1.size).toBigInt(1) - val y0 = mag2.sliceArray(0 until halfSize).toBigInt(1) - val y1 = mag2.sliceArray(halfSize until mag2.size).toBigInt(1) - - val z0 = x0 * y0 - val z2 = x1 * y1 - val z1 = (x0 - x1) * (y1 - y0) + z0 + z2 - - return (z2.shl(2 * halfSize * BASE_SIZE) + z1.shl(halfSize * BASE_SIZE) + z0).magnitude - } - private fun divideMagnitudeByUInt(mag: Magnitude, x: UInt): Magnitude { val resultLength = mag.size val result = Magnitude(resultLength) @@ -439,99 +414,65 @@ public fun UIntArray.toBigInt(sign: Byte): BigInt { return BigInt(sign, copyOf()) } +private val hexChToInt: MutableMap = hashMapOf( + '0' to 0, '1' to 1, '2' to 2, '3' to 3, + '4' to 4, '5' to 5, '6' to 6, '7' to 7, + '8' to 8, '9' to 9, 'A' to 10, 'B' to 11, + 'C' to 12, 'D' to 13, 'E' to 14, 'F' to 15 +) + /** - * Returns `null` if a valid number cannot be read from a string + * Returns null if a valid number can not be read from a string */ public fun String.parseBigInteger(): BigInt? { - if (isEmpty()) return null val sign: Int + val sPositive: String - val positivePartIndex = when (this[0]) { - '+' -> { + when { + this[0] == '+' -> { sign = +1 - 1 + sPositive = this.substring(1) } - '-' -> { + this[0] == '-' -> { sign = -1 - 1 + sPositive = this.substring(1) } else -> { + sPositive = this sign = +1 - 0 } } - var isEmpty = true + var res = BigInt.ZERO + var digitValue = BigInt.ONE + val sPositiveUpper = sPositive.uppercase() - return if (this.startsWith("0X", startIndex = positivePartIndex, ignoreCase = true)) { - // hex representation + if (sPositiveUpper.startsWith("0X")) { // hex representation + val sHex = sPositiveUpper.substring(2) - val uInts = ArrayList(length).apply { add(0U) } - var offset = 0 - fun addDigit(value: UInt) { - uInts[uInts.lastIndex] += value shl offset - offset += 4 - if (offset == 32) { - uInts.add(0U) - offset = 0 - } + for (ch in sHex.reversed()) { + if (ch == '_') continue + res += digitValue * (hexChToInt[ch] ?: return null) + digitValue *= 16.toBigInt() } - - for (index in lastIndex downTo positivePartIndex + 2) { - when (val ch = this[index]) { - '_' -> continue - in '0'..'9' -> addDigit((ch - '0').toUInt()) - in 'A'..'F' -> addDigit((ch - 'A').toUInt() + 10U) - in 'a'..'f' -> addDigit((ch - 'a').toUInt() + 10U) - else -> return null - } - isEmpty = false - } - - while (uInts.isNotEmpty() && uInts.last() == 0U) - uInts.removeLast() - - if (isEmpty) null else BigInt(sign.toByte(), uInts.toUIntArray()) - } else { + } else for (ch in sPositiveUpper.reversed()) { // decimal representation - - val positivePart = buildList(length) { - for (index in positivePartIndex until length) - when (val a = this@parseBigInteger[index]) { - '_' -> continue - in '0'..'9' -> add(a) - else -> return null - } + if (ch == '_') continue + if (ch !in '0'..'9') { + return null } - - val offset = positivePart.size % 9 - isEmpty = offset == 0 - - fun parseUInt(fromIndex: Int, toIndex: Int): UInt? { - var res = 0U - for (i in fromIndex until toIndex) { - res = res * 10U + (positivePart[i].digitToIntOrNull()?.toUInt() ?: return null) - } - return res - } - - var res = parseUInt(0, offset)?.toBigInt() ?: return null - - for (index in offset..positivePart.lastIndex step 9) { - isEmpty = false - res = res * 1_000_000_000U + (parseUInt(index, index + 9) ?: return null).toBigInt() - } - if (isEmpty) null else res * sign + res += digitValue * (ch.code - '0'.code) + digitValue *= 10.toBigInt() } + + return res * sign } -public val BigInt.algebra: BigIntField get() = BigIntField +public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer = + boxing(size, initializer) -public inline fun BigInt.Companion.buffer(size: Int, initializer: (Int) -> BigInt): Buffer = - Buffer.boxing(size, initializer) +public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer = + boxing(size, initializer) -public inline fun BigInt.Companion.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer = - Buffer.boxing(size, initializer) - -public val BigIntField.nd: BufferedRingOpsND - get() = BufferedRingOpsND(BufferRingOps(BigIntField)) +public fun AlgebraND.Companion.bigInt(vararg shape: Int): BufferedRingND = + BufferedRingND(shape, BigIntField, Buffer.Companion::bigInt) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt deleted file mode 100644 index af0bc4d9b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory - -public interface WithSize { - public val size: Int -} - -/** - * An algebra over [Buffer] - */ -public interface BufferAlgebra> : Algebra> { - public val elementAlgebra: A - public val elementBufferFactory: BufferFactory get() = elementAlgebra.bufferFactory - - public fun buffer(size: Int, vararg elements: T): Buffer { - require(elements.size == size) { "Expected $size elements but found ${elements.size}" } - return elementBufferFactory(size) { elements[it] } - } - - //TODO move to multi-receiver inline extension - public fun Buffer.map(block: A.(T) -> T): Buffer = mapInline(this, block) - - public fun Buffer.mapIndexed(block: A.(index: Int, arg: T) -> T): Buffer = mapIndexedInline(this, block) - - public fun Buffer.zip(other: Buffer, block: A.(left: T, right: T) -> T): Buffer = - zipInline(this, other, block) - - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { - val operationFunction = elementAlgebra.unaryOperationFunction(operation) - return { arg -> elementBufferFactory(arg.size) { operationFunction(arg[it]) } } - } - - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { - val operationFunction = elementAlgebra.binaryOperationFunction(operation) - return { left, right -> - elementBufferFactory(left.size) { operationFunction(left[it], right[it]) } - } - } -} - -/** - * Inline map - */ -private inline fun > BufferAlgebra.mapInline( - buffer: Buffer, - crossinline block: A.(T) -> T, -): Buffer = elementBufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) } - -/** - * Inline map - */ -private inline fun > BufferAlgebra.mapIndexedInline( - buffer: Buffer, - crossinline block: A.(index: Int, arg: T) -> T, -): Buffer = elementBufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) } - -/** - * Inline zip - */ -private inline fun > BufferAlgebra.zipInline( - l: Buffer, - r: Buffer, - crossinline block: A.(l: T, r: T) -> T, -): Buffer { - require(l.size == r.size) { "Incompatible buffer sizes. left: ${l.size}, right: ${r.size}" } - return elementBufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) } -} - -public fun BufferAlgebra.buffer(size: Int, initializer: (Int) -> T): Buffer { - return elementBufferFactory(size, initializer) -} - -public fun A.buffer(initializer: (Int) -> T): Buffer where A : BufferAlgebra, A : WithSize { - return elementBufferFactory(size, initializer) -} - -public fun > BufferAlgebra.sin(arg: Buffer): Buffer = - mapInline(arg) { sin(it) } - -public fun > BufferAlgebra.cos(arg: Buffer): Buffer = - mapInline(arg) { cos(it) } - -public fun > BufferAlgebra.tan(arg: Buffer): Buffer = - mapInline(arg) { tan(it) } - -public fun > BufferAlgebra.asin(arg: Buffer): Buffer = - mapInline(arg) { asin(it) } - -public fun > BufferAlgebra.acos(arg: Buffer): Buffer = - mapInline(arg) { acos(it) } - -public fun > BufferAlgebra.atan(arg: Buffer): Buffer = - mapInline(arg) { atan(it) } - -public fun > BufferAlgebra.exp(arg: Buffer): Buffer = - mapInline(arg) { exp(it) } - -public fun > BufferAlgebra.ln(arg: Buffer): Buffer = - mapInline(arg) { ln(it) } - -public fun > BufferAlgebra.sinh(arg: Buffer): Buffer = - mapInline(arg) { sinh(it) } - -public fun > BufferAlgebra.cosh(arg: Buffer): Buffer = - mapInline(arg) { cosh(it) } - -public fun > BufferAlgebra.tanh(arg: Buffer): Buffer = - mapInline(arg) { tanh(it) } - -public fun > BufferAlgebra.asinh(arg: Buffer): Buffer = - mapInline(arg) { asinh(it) } - -public fun > BufferAlgebra.acosh(arg: Buffer): Buffer = - mapInline(arg) { acosh(it) } - -public fun > BufferAlgebra.atanh(arg: Buffer): Buffer = - mapInline(arg) { atanh(it) } - -public fun > BufferAlgebra.pow(arg: Buffer, pow: Number): Buffer = - mapInline(arg) { it.pow(pow) } - - -public open class BufferRingOps>( - override val elementAlgebra: A, -) : BufferAlgebra, RingOps> { - - override fun add(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l + r } - override fun multiply(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l * r } - override fun Buffer.unaryMinus(): Buffer = map { -it } - - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = - super.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = - super.binaryOperationFunction(operation) -} - -public val IntRing.bufferAlgebra: BufferRingOps - get() = BufferRingOps(IntRing) - -public val ShortRing.bufferAlgebra: BufferRingOps - get() = BufferRingOps(ShortRing) - -public open class BufferFieldOps>( - elementAlgebra: A, -) : BufferRingOps(elementAlgebra), BufferAlgebra, FieldOps>, ScaleOperations> { - - // override fun add(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l + r } -// override fun multiply(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l * r } - override fun divide(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l / r } - - override fun scale(a: Buffer, value: Double): Buffer = a.map { scale(it, value) } - override fun Buffer.unaryMinus(): Buffer = map { -it } - - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = - super.binaryOperationFunction(operation) -} - -public class BufferField>( - elementAlgebra: A, - override val size: Int, -) : BufferFieldOps(elementAlgebra), Field>, WithSize { - - override val zero: Buffer = elementAlgebra.bufferFactory(size) { elementAlgebra.zero } - override val one: Buffer = elementAlgebra.bufferFactory(size) { elementAlgebra.one } -} - -/** - * Generate full buffer field from given buffer operations - */ -public fun > BufferFieldOps.withSize(size: Int): BufferField = - BufferField(elementAlgebra, size) - -//Double buffer specialization - -public fun BufferField.buffer(vararg elements: Number): Buffer { - require(elements.size == size) { "Expected $size elements but found ${elements.size}" } - return elementBufferFactory(size) { elements[it].toDouble() } -} - -public val > A.bufferAlgebra: BufferFieldOps - get() = BufferFieldOps(this) - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt deleted file mode 100644 index 2e6b63a92..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer - -/** - * [ExtendedField] over [DoubleBuffer]. - * - * @property size the size of buffers to operate on. - */ -public class DoubleBufferField(public val size: Int) : ExtendedField>, DoubleBufferOps() { - override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } - override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } - - override fun sinh(arg: Buffer): DoubleBuffer = super.sinh(arg) - - override fun cosh(arg: Buffer): DoubleBuffer = super.cosh(arg) - - override fun tanh(arg: Buffer): DoubleBuffer = super.tanh(arg) - - override fun asinh(arg: Buffer): DoubleBuffer = super.asinh(arg) - - override fun acosh(arg: Buffer): DoubleBuffer = super.acosh(arg) - - override fun atanh(arg: Buffer): DoubleBuffer = super.atanh(arg) - - override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (pow.isInteger()) { - arg.map { it.pow(pow.toInt()) } - } else { - arg.map { - if(it<0) throw IllegalArgumentException("Negative argument $it could not be raised to the fractional power") - it.pow(pow.toDouble()) - } - } - - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = - super.unaryOperationFunction(operation) -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt deleted file mode 100644 index 74b41be9d..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.linear.Point -import space.kscience.kmath.structures.* -import kotlin.math.pow -import kotlin.math.sqrt - -/** - * [ExtendedFieldOps] over [DoubleBuffer]. - */ -public abstract class DoubleBufferOps : BufferAlgebra, ExtendedFieldOps>, - Norm, Double> { - - override val elementAlgebra: DoubleField get() = DoubleField - - override val elementBufferFactory: MutableBufferFactory get() = elementAlgebra.bufferFactory - - @Suppress("OVERRIDE_BY_INLINE") - @OptIn(UnstableKMathAPI::class) - final override inline fun Buffer.map(block: DoubleField.(Double) -> Double): DoubleBuffer = - DoubleArray(size) { DoubleField.block(getDouble(it)) }.asBuffer() - - - @OptIn(UnstableKMathAPI::class) - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun Buffer.mapIndexed(block: DoubleField.(index: Int, arg: Double) -> Double): DoubleBuffer = - DoubleBuffer(size) { DoubleField.block(it, getDouble(it)) } - - @OptIn(UnstableKMathAPI::class) - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun Buffer.zip( - other: Buffer, - block: DoubleField.(left: Double, right: Double) -> Double, - ): DoubleBuffer { - require(size == other.size) { "Incompatible buffer sizes. left: ${size}, right: ${other.size}" } - return DoubleBuffer(size) { DoubleField.block(getDouble(it), other.getDouble(it)) } - } - - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = - super.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = - super.binaryOperationFunction(operation) - - override fun Buffer.unaryMinus(): DoubleBuffer = map { -it } - - override fun add(left: Buffer, right: Buffer): DoubleBuffer { - require(right.size == left.size) { - "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " - } - - return if (left is DoubleBuffer && right is DoubleBuffer) { - val aArray = left.array - val bArray = right.array - DoubleBuffer(DoubleArray(left.size) { aArray[it] + bArray[it] }) - } else DoubleBuffer(DoubleArray(left.size) { left[it] + right[it] }) - } - - override fun Buffer.plus(arg: Buffer): DoubleBuffer = add(this, arg) - - override fun Buffer.minus(arg: Buffer): DoubleBuffer { - require(arg.size == this.size) { - "The size of the first buffer ${this.size} should be the same as for second one: ${arg.size} " - } - - return if (this is DoubleBuffer && arg is DoubleBuffer) { - val aArray = this.array - val bArray = arg.array - DoubleBuffer(DoubleArray(this.size) { aArray[it] - bArray[it] }) - } else DoubleBuffer(DoubleArray(this.size) { this[it] - arg[it] }) - } - - // -// override fun multiply(a: Buffer, k: Number): RealBuffer { -// val kValue = k.toDouble() -// -// return if (a is RealBuffer) { -// val aArray = a.array -// RealBuffer(DoubleArray(a.size) { aArray[it] * kValue }) -// } else RealBuffer(DoubleArray(a.size) { a[it] * kValue }) -// } -// -// override fun divide(a: Buffer, k: Number): RealBuffer { -// val kValue = k.toDouble() -// -// return if (a is RealBuffer) { -// val aArray = a.array -// RealBuffer(DoubleArray(a.size) { aArray[it] / kValue }) -// } else RealBuffer(DoubleArray(a.size) { a[it] / kValue }) -// } - - @UnstableKMathAPI - override fun multiply(left: Buffer, right: Buffer): DoubleBuffer { - require(right.size == left.size) { - "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " - } - - return if (left is DoubleBuffer && right is DoubleBuffer) { - val aArray = left.array - val bArray = right.array - DoubleBuffer(DoubleArray(left.size) { aArray[it] * bArray[it] }) - } else DoubleBuffer(DoubleArray(left.size) { left[it] * right[it] }) - } - - override fun divide(left: Buffer, right: Buffer): DoubleBuffer { - require(right.size == left.size) { - "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " - } - - return if (left is DoubleBuffer && right is DoubleBuffer) { - val aArray = left.array - val bArray = right.array - DoubleBuffer(DoubleArray(left.size) { aArray[it] / bArray[it] }) - } else DoubleBuffer(DoubleArray(left.size) { left[it] / right[it] }) - } - - override fun sin(arg: Buffer): DoubleBuffer = arg.map { sin(it) } - - override fun cos(arg: Buffer): DoubleBuffer = arg.map { cos(it) } - - override fun tan(arg: Buffer): DoubleBuffer = arg.map { tan(it) } - - override fun asin(arg: Buffer): DoubleBuffer = arg.map { asin(it) } - - override fun acos(arg: Buffer): DoubleBuffer = arg.map { acos(it) } - - override fun atan(arg: Buffer): DoubleBuffer = arg.map { atan(it) } - - override fun sinh(arg: Buffer): DoubleBuffer = arg.map { sinh(it) } - - override fun cosh(arg: Buffer): DoubleBuffer = arg.map { cosh(it) } - - override fun tanh(arg: Buffer): DoubleBuffer = arg.map { tanh(it) } - - override fun asinh(arg: Buffer): DoubleBuffer = arg.map { asinh(it) } - - override fun acosh(arg: Buffer): DoubleBuffer = arg.map { acosh(it) } - - override fun atanh(arg: Buffer): DoubleBuffer = arg.map { atanh(it) } - - override fun exp(arg: Buffer): DoubleBuffer = arg.map { exp(it) } - - override fun ln(arg: Buffer): DoubleBuffer = arg.map { ln(it) } - - override fun norm(arg: Buffer): Double = DoubleL2Norm.norm(arg) - - override fun scale(a: Buffer, value: Double): DoubleBuffer = a.map { it * value } - - override fun power(arg: Buffer, pow: Number): Buffer = if (pow is Int) { - arg.map { it.pow(pow) } - } else { - arg.map { it.pow(pow.toDouble()) } - } - - public companion object : DoubleBufferOps() -} - -public object DoubleL2Norm : Norm, Double> { - override fun norm(arg: Point): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) -} - -public fun DoubleBufferOps.sum(buffer: Buffer): Double = buffer.reduce(Double::plus) - -/** - * Sum of elements using given [conversion] - */ -public inline fun DoubleBufferOps.sumOf(buffer: Buffer, conversion: (T) -> Double): Double = - buffer.fold(0.0) { acc, value -> acc + conversion(value) } - -public fun DoubleBufferOps.average(buffer: Buffer): Double = sum(buffer) / buffer.size - -/** - * Average of elements using given [conversion] - */ -public inline fun DoubleBufferOps.averageOf(buffer: Buffer, conversion: (T) -> Double): Double = - sumOf(buffer, conversion) / buffer.size - -public fun DoubleBufferOps.dispersion(buffer: Buffer): Double { - val av = average(buffer) - return buffer.fold(0.0) { acc, value -> acc + (value - av).pow(2) } / buffer.size -} - -public fun DoubleBufferOps.std(buffer: Buffer): Double = sqrt(dispersion(buffer)) - -public fun DoubleBufferOps.covariance(x: Buffer, y: Buffer): Double { - require(x.size == y.size) { "Expected buffers of the same size, but x.size == ${x.size} and y.size == ${y.size}" } - val xMean = average(x) - val yMean = average(y) - var sum = 0.0 - x.indices.forEach { - sum += (x[it] - xMean) * (y[it] - yMean) - } - return sum / (x.size - 1) -} - - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt deleted file mode 100644 index 7aa5aed80..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.symbol - -/** - * An algebra for generic boolean logic - */ -@UnstableKMathAPI -public interface LogicAlgebra : Algebra { - - /** - * Represent constant [Boolean] as [T] - */ - public fun const(boolean: Boolean): T - - override fun bindSymbolOrNull(value: String): T? = value.lowercase().toBooleanStrictOrNull()?.let(::const) - - override fun unaryOperation(operation: String, arg: T): T = when (operation) { - Boolean::not.name -> arg.not() - else -> super.unaryOperation(operation, arg) - } - - override fun unaryOperationFunction(operation: String): (arg: T) -> T = { unaryOperation(operation, it) } - - override fun binaryOperation(operation: String, left: T, right: T): T = when (operation) { - Boolean::and.name -> left.and(right) - Boolean::or.name -> left.or(right) - else -> super.binaryOperation(operation, left, right) - } - - override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = { l, r -> - binaryOperation(operation, l, r) - } - - /** - * Logic 'not' - */ - public operator fun T.not(): T - - /** - * Logic 'and' - */ - public infix fun T.and(other: T): T - - /** - * Logic 'or' - */ - public infix fun T.or(other: T): T - - /** - * Logic 'xor' - */ - public infix fun T.xor(other: T): T - - - public companion object { - public val TRUE: Symbol by symbol - public val FALSE: Symbol by symbol - } -} - -/** - * An implementation of [LogicAlgebra] for primitive booleans - */ -@UnstableKMathAPI -@Suppress("EXTENSION_SHADOWED_BY_MEMBER") -public object BooleanAlgebra : LogicAlgebra { - - override fun const(boolean: Boolean): Boolean = boolean - - override fun Boolean.not(): Boolean = !this - - override fun Boolean.and(other: Boolean): Boolean = this && other - - override fun Boolean.or(other: Boolean): Boolean = this || other - - override fun Boolean.xor(other: Boolean): Boolean = this xor other -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt index 9bcfb00a2..6a35828ee 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt @@ -1,11 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.operations -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI import kotlin.math.E import kotlin.math.PI @@ -26,11 +26,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically dispatches a binary operation with the certain name with numeric first argument. * - * Implementations must fulfil the following requirements: + * This function must follow two properties: * - * 1. If operation is not defined in the structure, then function throws [kotlin.IllegalStateException]. - * 1. Equivalence to [leftSideNumberOperation]: for any `a`, `b`, and `c`, - * `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with the other [leftSideNumberOperation] overload: + * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. * * @param operation the name of operation. * @return an operation. @@ -41,11 +41,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically invokes a binary operation with the certain name with numeric first argument. * - * Implementations must fulfil the following requirements: + * This function must follow two properties: * - * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. - * 1. Equivalence to [leftSideNumberOperation]: for any `a`, `b`, and `c`, - * `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second [leftSideNumberOperation] overload: + * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -58,11 +58,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically dispatches a binary operation with the certain name with numeric first argument. * - * Implementations must fulfil the following requirements: + * This function must follow two properties: * - * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. - * 1. Equivalence to [rightSideNumberOperation]: for any `a`, `b`, and `c`, - * `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: + * i.e. `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @return an operation. @@ -73,11 +73,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically invokes a binary operation with the certain name with numeric second argument. * - * Implementations must fulfil the following requirements: + * This function must follow two properties: * - * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. - * 1. Equivalence to [rightSideNumberOperationFunction]: for any `a`, `b`, and `c`, - * `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: + * i.e. `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -87,7 +87,7 @@ public interface NumericAlgebra : Algebra { public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = rightSideNumberOperationFunction(operation)(left, right) - override fun bindSymbolOrNull(value: String): T? = when (value) { + public override fun bindSymbolOrNull(value: String): T? = when (value) { "pi" -> number(PI) "e" -> number(E) else -> super.bindSymbolOrNull(value) @@ -97,12 +97,14 @@ public interface NumericAlgebra : Algebra { /** * The π mathematical constant. */ -public val NumericAlgebra.pi: T get() = bindSymbolOrNull("pi") ?: number(PI) +public val NumericAlgebra.pi: T + get() = bindSymbolOrNull("pi") ?: number(PI) /** * The *e* mathematical constant. */ -public val NumericAlgebra.e: T get() = number(E) +public val NumericAlgebra.e: T + get() = number(E) /** * Scale by scalar operations @@ -139,10 +141,10 @@ public interface ScaleOperations : Algebra { * Multiplication of this number by element. * * @receiver the multiplier. - * @param arg the multiplicand. + * @param b the multiplicand. * @return the product. */ - public operator fun Number.times(arg: T): T = arg * this + public operator fun Number.times(b: T): T = b * this } /** @@ -150,38 +152,38 @@ public interface ScaleOperations : Algebra { * TODO to be removed and replaced by extensions after multiple receivers are there */ @UnstableKMathAPI -public interface NumbersAddOps : RingOps, NumericAlgebra { +public interface NumbersAddOperations : Ring, NumericAlgebra { /** * Addition of element and scalar. * * @receiver the augend. - * @param other the addend. + * @param b the addend. */ - public operator fun T.plus(other: Number): T = this + number(other) + public operator fun T.plus(b: Number): T = this + number(b) /** * Addition of scalar and element. * * @receiver the augend. - * @param other the addend. + * @param b the addend. */ - public operator fun Number.plus(other: T): T = other + this + public operator fun Number.plus(b: T): T = b + this /** * Subtraction of element from number. * * @receiver the minuend. - * @param other the subtrahend. + * @param b the subtrahend. * @receiver the difference. */ - public operator fun T.minus(other: Number): T = this - number(other) + public operator fun T.minus(b: Number): T = this - number(b) /** * Subtraction of number from element. * * @receiver the minuend. - * @param other the subtrahend. + * @param b the subtrahend. * @receiver the difference. */ - public operator fun Number.minus(other: T): T = -other + this + public operator fun Number.minus(b: T): T = -b + this } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt index c24394add..8e3e6c777 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt @@ -1,10 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.operations +import space.kscience.kmath.misc.UnstableKMathAPI + /** * A container for trigonometric operations for specific type. * @@ -75,20 +77,49 @@ public interface TrigonometricOperations : Algebra { } /** - * Check if number is an integer from platform point of view + * Computes the sine of [arg]. */ -public expect fun Number.isInteger(): Boolean +@UnstableKMathAPI +public fun >> sin(arg: T): T = arg.context.sin(arg) + +/** + * Computes the cosine of [arg]. + */ +@UnstableKMathAPI +public fun >> cos(arg: T): T = arg.context.cos(arg) + +/** + * Computes the tangent of [arg]. + */ +@UnstableKMathAPI +public fun >> tan(arg: T): T = arg.context.tan(arg) + +/** + * Computes the inverse sine of [arg]. + */ +@UnstableKMathAPI +public fun >> asin(arg: T): T = arg.context.asin(arg) + +/** + * Computes the inverse cosine of [arg]. + */ +@UnstableKMathAPI +public fun >> acos(arg: T): T = arg.context.acos(arg) + +/** + * Computes the inverse tangent of [arg]. + */ +@UnstableKMathAPI +public fun >> atan(arg: T): T = arg.context.atan(arg) /** * A context extension to include power operations based on exponentiation. * * @param T the type of element of this structure. */ -public interface PowerOperations : FieldOps { - +public interface PowerOperations : Algebra { /** - * Raises [arg] to a power if possible (negative number could not be raised to a fractional power). - * Throws [IllegalArgumentException] if not possible. + * Raises [arg] to the power [pow]. */ public fun power(arg: T, pow: Number): T @@ -115,6 +146,27 @@ public interface PowerOperations : FieldOps { } } +/** + * Raises this element to the power [pow]. + * + * @receiver the base. + * @param power the exponent. + * @return the base raised to the power. + */ +@UnstableKMathAPI +public infix fun >> T.pow(power: Double): T = context.power(this, power) + +/** + * Computes the square root of the value [arg]. + */ +@UnstableKMathAPI +public fun >> sqrt(arg: T): T = arg pow 0.5 + +/** + * Computes the square of the value [arg]. + */ +@UnstableKMathAPI +public fun >> sqr(arg: T): T = arg pow 2.0 /** * A container for operations related to `exp` and `ln` functions. @@ -205,6 +257,55 @@ public interface ExponentialOperations : Algebra { } } +/** + * The identifier of exponential function. + */ +@UnstableKMathAPI +public fun >> exp(arg: T): T = arg.context.exp(arg) + +/** + * The identifier of natural logarithm. + */ +@UnstableKMathAPI +public fun >> ln(arg: T): T = arg.context.ln(arg) + + +/** + * Computes the hyperbolic sine of [arg]. + */ +@UnstableKMathAPI +public fun >> sinh(arg: T): T = arg.context.sinh(arg) + +/** + * Computes the hyperbolic cosine of [arg]. + */ +@UnstableKMathAPI +public fun >> cosh(arg: T): T = arg.context.cosh(arg) + +/** + * Computes the hyperbolic tangent of [arg]. + */ +@UnstableKMathAPI +public fun >> tanh(arg: T): T = arg.context.tanh(arg) + +/** + * Computes the inverse hyperbolic sine of [arg]. + */ +@UnstableKMathAPI +public fun >> asinh(arg: T): T = arg.context.asinh(arg) + +/** + * Computes the inverse hyperbolic cosine of [arg]. + */ +@UnstableKMathAPI +public fun >> acosh(arg: T): T = arg.context.acosh(arg) + +/** + * Computes the inverse hyperbolic tangent of [arg]. + */ +@UnstableKMathAPI +public fun >> atanh(arg: T): T = arg.context.atanh(arg) + /** * A container for norm functional on element. * @@ -213,8 +314,13 @@ public interface ExponentialOperations : Algebra { */ public interface Norm { /** - * Computes the norm of [arg] (i.e., absolute value or vector length). + * Computes the norm of [arg] (i.e. absolute value or vector length). */ public fun norm(arg: T): R } +/** + * Computes the norm of [arg] (i.e. absolute value or vector length). + */ +@UnstableKMathAPI +public fun >, R> norm(arg: T): R = arg.context.norm(arg) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt index ddf599240..b8670553d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt @@ -1,87 +1,58 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.operations -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.structures.Buffer - /** - * Returns the sum of all elements in the iterable in this [Group]. + * Returns the sum of all elements in the iterable in this [Ring]. * * @receiver the algebra that provides addition. * @param data the iterable to sum up. * @return the sum. */ -@PerformancePitfall("Potential boxing access to buffer elements") -public fun Group.sum(data: Buffer): T = data.fold(zero) { left, right -> +public fun Ring.sum(data: Iterable): T = data.fold(zero) { left, right -> add(left, right) } /** - * Returns the sum of all elements in the iterable in this [Group]. - * - * @receiver the algebra that provides addition. - * @param data the iterable to sum up. - * @return the sum. - */ -public fun Group.sum(data: Iterable): T = data.fold(zero) { left, right -> - add(left, right) -} - -//TODO replace by sumOf with multi-receivers - -/** - * Returns the sum of all elements in the sequence in this [Group]. + * Returns the sum of all elements in the sequence in this [Ring]. * * @receiver the algebra that provides addition. * @param data the sequence to sum up. * @return the sum. */ -public fun Group.sum(data: Sequence): T = data.fold(zero) { left, right -> +public fun Ring.sum(data: Sequence): T = data.fold(zero) { left, right -> add(left, right) } /** - * Returns an average value of elements in the iterable in this [Group]. + * Returns an average value of elements in the iterable in this [Ring]. * * @receiver the algebra that provides addition and division. * @param data the iterable to find average. * @return the average value. * @author Iaroslav Postovalov */ -@PerformancePitfall("Potential boxing access to buffer elements") -public fun S.average(data: Buffer): T where S : Group, S : ScaleOperations = - sum(data) / data.size - -/** - * Returns an average value of elements in the iterable in this [Group]. - * - * @receiver the algebra that provides addition and division. - * @param data the iterable to find average. - * @return the average value. - * @author Iaroslav Postovalov - */ -public fun S.average(data: Iterable): T where S : Group, S : ScaleOperations = +public fun S.average(data: Iterable): T where S : Ring, S : ScaleOperations = sum(data) / data.count() /** - * Returns an average value of elements in the sequence in this [Group]. + * Returns an average value of elements in the sequence in this [Ring]. * * @receiver the algebra that provides addition and division. * @param data the sequence to find average. * @return the average value. * @author Iaroslav Postovalov */ -public fun S.average(data: Sequence): T where S : Group, S : ScaleOperations = +public fun S.average(data: Sequence): T where S : Ring, S : ScaleOperations = sum(data) / data.count() /** * Absolute of the comparable [value] */ -public fun > Group.abs(value: T): T = if (value > zero) value else -value +public fun > Ring.abs(value: T): T = if (value > zero) value else -value /** * Returns the sum of all elements in the iterable in provided space. @@ -90,18 +61,7 @@ public fun > Group.abs(value: T): T = if (value > zero) val * @param group the algebra that provides addition. * @return the sum. */ -public fun Iterable.sumWith(group: Group): T = group.sum(this) - -/** - * Sum extracted elements of [Iterable] with given [group] - * - * @receiver the collection to sum up. - * @param group tha algebra that provides addition - * @param extractor the (inline) lambda function to extract value - */ -public inline fun Iterable.sumWithGroupOf(group: Group, extractor: (T) -> R): R = this.fold(group.zero) { left: R, right: T -> - group.add(left, extractor(right)) -} +public fun Iterable.sumWith(group: Ring): T = group.sum(this) /** * Returns the sum of all elements in the sequence in provided space. @@ -110,26 +70,61 @@ public inline fun Iterable.sumWithGroupOf(group: Group, extractor: * @param group the algebra that provides addition. * @return the sum. */ -public fun Sequence.sumWith(group: Group): T = group.sum(this) +public fun Sequence.sumWith(group: Ring): T = group.sum(this) /** - * Returns an average value of elements in the iterable in this [Group]. + * Returns an average value of elements in the iterable in this [Ring]. * * @receiver the iterable to find average. * @param space the algebra that provides addition and division. * @return the average value. * @author Iaroslav Postovalov */ -public fun Iterable.averageWith(space: S): T where S : Group, S : ScaleOperations = +public fun Iterable.averageWith(space: S): T where S : Ring, S : ScaleOperations = space.average(this) /** - * Returns an average value of elements in the sequence in this [Group]. + * Returns an average value of elements in the sequence in this [Ring]. * * @receiver the sequence to find average. * @param space the algebra that provides addition and division. * @return the average value. * @author Iaroslav Postovalov */ -public fun Sequence.averageWith(space: S): T where S : Group, S : ScaleOperations = +public fun Sequence.averageWith(space: S): T where S : Ring, S : ScaleOperations = space.average(this) + +//TODO optimized power operation + +/** + * Raises [arg] to the natural power [power]. + * + * @receiver the algebra to provide multiplication. + * @param arg the base. + * @param power the exponent. + * @return the base raised to the power. + */ +public fun Ring.power(arg: T, power: Int): T { + require(power >= 0) { "The power can't be negative." } + require(power != 0 || arg != zero) { "The $zero raised to $power is not defined." } + if (power == 0) return one + var res = arg + repeat(power - 1) { res *= arg } + return res +} + +/** + * Raises [arg] to the integer power [power]. + * + * @receiver the algebra to provide multiplication and division. + * @param arg the base. + * @param power the exponent. + * @return the base raised to the power. + * @author Iaroslav Postovalov + */ +public fun Field.power(arg: T, power: Int): T { + require(power != 0 || arg != zero) { "The $zero raised to $power is not defined." } + if (power == 0) return one + if (power < 0) return one / (this as Ring).power(arg, -power) + return (this as Ring).power(arg, power) +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 224ca1daf..3b0abf657 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -1,33 +1,31 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("NOTHING_TO_INLINE") + package space.kscience.kmath.operations -import space.kscience.kmath.structures.* import kotlin.math.pow as kpow - /** * Advanced Number-like semifield that implements basic operations. */ -public interface ExtendedFieldOps : - FieldOps, +public interface ExtendedFieldOperations : + FieldOperations, TrigonometricOperations, - ExponentialOperations, - ScaleOperations, - PowerOperations { - override fun tan(arg: T): T = sin(arg) / cos(arg) - override fun tanh(arg: T): T = sinh(arg) / cosh(arg) + PowerOperations, + ExponentialOperations { + public override fun tan(arg: T): T = sin(arg) / cos(arg) + public override fun tanh(arg: T): T = sinh(arg) / cosh(arg) - override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { + public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { TrigonometricOperations.COS_OPERATION -> ::cos TrigonometricOperations.SIN_OPERATION -> ::sin TrigonometricOperations.TAN_OPERATION -> ::tan TrigonometricOperations.ACOS_OPERATION -> ::acos TrigonometricOperations.ASIN_OPERATION -> ::asin TrigonometricOperations.ATAN_OPERATION -> ::atan + PowerOperations.SQRT_OPERATION -> ::sqrt ExponentialOperations.EXP_OPERATION -> ::exp ExponentialOperations.LN_OPERATION -> ::ln ExponentialOperations.COSH_OPERATION -> ::cosh @@ -36,27 +34,28 @@ public interface ExtendedFieldOps : ExponentialOperations.ACOSH_OPERATION -> ::acosh ExponentialOperations.ASINH_OPERATION -> ::asinh ExponentialOperations.ATANH_OPERATION -> ::atanh - else -> super.unaryOperationFunction(operation) + else -> super.unaryOperationFunction(operation) } } /** * Advanced Number-like field that implements basic operations. */ -public interface ExtendedField : ExtendedFieldOps, Field, NumericAlgebra { - override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 - override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 - override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) - override fun asinh(arg: T): T = ln(sqrt(arg * arg + one) + arg) - override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) - override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0 +public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra, ScaleOperations { + public override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 + public override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 + public override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) + public override fun asinh(arg: T): T = ln(sqrt(arg * arg + one) + arg) + public override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) + public override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0 - override fun unaryOperationFunction(operation: String): (arg: T) -> T { - return if (operation == PowerOperations.SQRT_OPERATION) ::sqrt - else super.unaryOperationFunction(operation) + public override fun bindSymbol(value: String): T = when (value) { + "pi" -> pi + "e" -> e + else -> super.bindSymbol(value) } - override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = + public override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = when (operation) { PowerOperations.POW_OPERATION -> ::power else -> super.rightSideNumberOperationFunction(operation) @@ -66,207 +65,187 @@ public interface ExtendedField : ExtendedFieldOps, Field, NumericAlgebr /** * A field for [Double] without boxing. Does not produce appropriate field element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object DoubleField : ExtendedField, Norm, ScaleOperations { - override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::DoubleBuffer) + public override inline val zero: Double get() = 0.0 + public override inline val one: Double get() = 1.0 - override inline val zero: Double get() = 0.0 - override inline val one: Double get() = 1.0 + public override fun number(value: Number): Double = value.toDouble() - override inline fun number(value: Number): Double = value.toDouble() - - override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = + public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { - PowerOperations.POW_OPERATION -> { l, r -> l.kpow(r) } + PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - override inline fun add(left: Double, right: Double): Double = left + right + public override inline fun add(a: Double, b: Double): Double = a + b - override inline fun multiply(left: Double, right: Double): Double = left * right - override inline fun divide(left: Double, right: Double): Double = left / right + public override inline fun multiply(a: Double, b: Double): Double = a * b + public override inline fun divide(a: Double, b: Double): Double = a / b - override inline fun scale(a: Double, value: Double): Double = a * value + public override fun scale(a: Double, value: Double): Double = a * value - override inline fun sin(arg: Double): Double = kotlin.math.sin(arg) - override inline fun cos(arg: Double): Double = kotlin.math.cos(arg) - override inline fun tan(arg: Double): Double = kotlin.math.tan(arg) - override inline fun acos(arg: Double): Double = kotlin.math.acos(arg) - override inline fun asin(arg: Double): Double = kotlin.math.asin(arg) - override inline fun atan(arg: Double): Double = kotlin.math.atan(arg) + public override inline fun sin(arg: Double): Double = kotlin.math.sin(arg) + public override inline fun cos(arg: Double): Double = kotlin.math.cos(arg) + public override inline fun tan(arg: Double): Double = kotlin.math.tan(arg) + public override inline fun acos(arg: Double): Double = kotlin.math.acos(arg) + public override inline fun asin(arg: Double): Double = kotlin.math.asin(arg) + public override inline fun atan(arg: Double): Double = kotlin.math.atan(arg) - override inline fun sinh(arg: Double): Double = kotlin.math.sinh(arg) - override inline fun cosh(arg: Double): Double = kotlin.math.cosh(arg) - override inline fun tanh(arg: Double): Double = kotlin.math.tanh(arg) - override inline fun asinh(arg: Double): Double = kotlin.math.asinh(arg) - override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg) - override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg) + public override inline fun sinh(arg: Double): Double = kotlin.math.sinh(arg) + public override inline fun cosh(arg: Double): Double = kotlin.math.cosh(arg) + public override inline fun tanh(arg: Double): Double = kotlin.math.tanh(arg) + public override inline fun asinh(arg: Double): Double = kotlin.math.asinh(arg) + public override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg) + public override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg) - override fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg) - override fun power(arg: Double, pow: Number): Double = when { - pow.isInteger() -> arg.kpow(pow.toInt()) - arg < 0 -> throw IllegalArgumentException("Can't raise negative $arg to a fractional power $pow") - else -> arg.kpow(pow.toDouble()) - } + public override inline fun power(arg: Double, pow: Number): Double = arg.kpow(pow.toDouble()) + public override inline fun exp(arg: Double): Double = kotlin.math.exp(arg) + public override inline fun ln(arg: Double): Double = kotlin.math.ln(arg) - override inline fun exp(arg: Double): Double = kotlin.math.exp(arg) - override inline fun ln(arg: Double): Double = kotlin.math.ln(arg) + public override inline fun norm(arg: Double): Double = abs(arg) - override inline fun norm(arg: Double): Double = abs(arg) - - override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(arg: Double): Double = this + arg - override inline fun Double.minus(arg: Double): Double = this - arg - override inline fun Double.times(arg: Double): Double = this * arg - override inline fun Double.div(arg: Double): Double = this / arg + public override inline fun Double.unaryMinus(): Double = -this + public override inline fun Double.plus(b: Double): Double = this + b + public override inline fun Double.minus(b: Double): Double = this - b + public override inline fun Double.times(b: Double): Double = this * b + public override inline fun Double.div(b: Double): Double = this / b } -public val Double.Companion.algebra: DoubleField get() = DoubleField - /** * A field for [Float] without boxing. Does not produce appropriate field element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object FloatField : ExtendedField, Norm { - override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::FloatBuffer) + public override inline val zero: Float get() = 0.0f + public override inline val one: Float get() = 1.0f - override inline val zero: Float get() = 0.0f - override inline val one: Float get() = 1.0f + public override fun number(value: Number): Float = value.toFloat() - override fun number(value: Number): Float = value.toFloat() - - override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = + public override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = when (operation) { - PowerOperations.POW_OPERATION -> { l, r -> l.kpow(r) } + PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - override inline fun add(left: Float, right: Float): Float = left + right - override fun scale(a: Float, value: Double): Float = a * value.toFloat() + public override inline fun add(a: Float, b: Float): Float = a + b + public override fun scale(a: Float, value: Double): Float = a * value.toFloat() - override inline fun multiply(left: Float, right: Float): Float = left * right + public override inline fun multiply(a: Float, b: Float): Float = a * b - override inline fun divide(left: Float, right: Float): Float = left / right + public override inline fun divide(a: Float, b: Float): Float = a / b - override inline fun sin(arg: Float): Float = kotlin.math.sin(arg) - override inline fun cos(arg: Float): Float = kotlin.math.cos(arg) - override inline fun tan(arg: Float): Float = kotlin.math.tan(arg) - override inline fun acos(arg: Float): Float = kotlin.math.acos(arg) - override inline fun asin(arg: Float): Float = kotlin.math.asin(arg) - override inline fun atan(arg: Float): Float = kotlin.math.atan(arg) + public override inline fun sin(arg: Float): Float = kotlin.math.sin(arg) + public override inline fun cos(arg: Float): Float = kotlin.math.cos(arg) + public override inline fun tan(arg: Float): Float = kotlin.math.tan(arg) + public override inline fun acos(arg: Float): Float = kotlin.math.acos(arg) + public override inline fun asin(arg: Float): Float = kotlin.math.asin(arg) + public override inline fun atan(arg: Float): Float = kotlin.math.atan(arg) - override inline fun sinh(arg: Float): Float = kotlin.math.sinh(arg) - override inline fun cosh(arg: Float): Float = kotlin.math.cosh(arg) - override inline fun tanh(arg: Float): Float = kotlin.math.tanh(arg) - override inline fun asinh(arg: Float): Float = kotlin.math.asinh(arg) - override inline fun acosh(arg: Float): Float = kotlin.math.acosh(arg) - override inline fun atanh(arg: Float): Float = kotlin.math.atanh(arg) + public override inline fun sinh(arg: Float): Float = kotlin.math.sinh(arg) + public override inline fun cosh(arg: Float): Float = kotlin.math.cosh(arg) + public override inline fun tanh(arg: Float): Float = kotlin.math.tanh(arg) + public override inline fun asinh(arg: Float): Float = kotlin.math.asinh(arg) + public override inline fun acosh(arg: Float): Float = kotlin.math.acosh(arg) + public override inline fun atanh(arg: Float): Float = kotlin.math.atanh(arg) - override inline fun sqrt(arg: Float): Float = kotlin.math.sqrt(arg) - override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat()) + public override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat()) + public override inline fun exp(arg: Float): Float = kotlin.math.exp(arg) + public override inline fun ln(arg: Float): Float = kotlin.math.ln(arg) - override inline fun exp(arg: Float): Float = kotlin.math.exp(arg) - override inline fun ln(arg: Float): Float = kotlin.math.ln(arg) + public override inline fun norm(arg: Float): Float = abs(arg) - override inline fun norm(arg: Float): Float = abs(arg) - - override inline fun Float.unaryMinus(): Float = -this - override inline fun Float.plus(arg: Float): Float = this + arg - override inline fun Float.minus(arg: Float): Float = this - arg - override inline fun Float.times(arg: Float): Float = this * arg - override inline fun Float.div(arg: Float): Float = this / arg + public override inline fun Float.unaryMinus(): Float = -this + public override inline fun Float.plus(b: Float): Float = this + b + public override inline fun Float.minus(b: Float): Float = this - b + public override inline fun Float.times(b: Float): Float = this * b + public override inline fun Float.div(b: Float): Float = this / b } -public val Float.Companion.algebra: FloatField get() = FloatField - /** * A field for [Int] without boxing. Does not produce corresponding ring element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object IntRing : Ring, Norm, NumericAlgebra { - override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::IntBuffer) + public override inline val zero: Int + get() = 0 - override inline val zero: Int get() = 0 - override inline val one: Int get() = 1 + public override inline val one: Int + get() = 1 - override fun number(value: Number): Int = value.toInt() - override inline fun add(left: Int, right: Int): Int = left + right - override inline fun multiply(left: Int, right: Int): Int = left * right - override inline fun norm(arg: Int): Int = abs(arg) + public override fun number(value: Number): Int = value.toInt() + public override inline fun add(a: Int, b: Int): Int = a + b + public override inline fun multiply(a: Int, b: Int): Int = a * b + public override inline fun norm(arg: Int): Int = abs(arg) - override inline fun Int.unaryMinus(): Int = -this - override inline fun Int.plus(arg: Int): Int = this + arg - override inline fun Int.minus(arg: Int): Int = this - arg - override inline fun Int.times(arg: Int): Int = this * arg + public override inline fun Int.unaryMinus(): Int = -this + public override inline fun Int.plus(b: Int): Int = this + b + public override inline fun Int.minus(b: Int): Int = this - b + public override inline fun Int.times(b: Int): Int = this * b } -public val Int.Companion.algebra: IntRing get() = IntRing - /** * A field for [Short] without boxing. Does not produce appropriate ring element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object ShortRing : Ring, Norm, NumericAlgebra { - override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::ShortBuffer) + public override inline val zero: Short + get() = 0 - override inline val zero: Short get() = 0 - override inline val one: Short get() = 1 + public override inline val one: Short + get() = 1 - override fun number(value: Number): Short = value.toShort() - override inline fun add(left: Short, right: Short): Short = (left + right).toShort() - override inline fun multiply(left: Short, right: Short): Short = (left * right).toShort() - override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort() + public override fun number(value: Number): Short = value.toShort() + public override inline fun add(a: Short, b: Short): Short = (a + b).toShort() + public override inline fun multiply(a: Short, b: Short): Short = (a * b).toShort() + public override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort() - override inline fun Short.unaryMinus(): Short = (-this).toShort() - override inline fun Short.plus(arg: Short): Short = (this + arg).toShort() - override inline fun Short.minus(arg: Short): Short = (this - arg).toShort() - override inline fun Short.times(arg: Short): Short = (this * arg).toShort() + public override inline fun Short.unaryMinus(): Short = (-this).toShort() + public override inline fun Short.plus(b: Short): Short = (this + b).toShort() + public override inline fun Short.minus(b: Short): Short = (this - b).toShort() + public override inline fun Short.times(b: Short): Short = (this * b).toShort() } -public val Short.Companion.algebra: ShortRing get() = ShortRing - /** * A field for [Byte] without boxing. Does not produce appropriate ring element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object ByteRing : Ring, Norm, NumericAlgebra { - override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::ByteBuffer) + public override inline val zero: Byte + get() = 0 - override inline val zero: Byte get() = 0 - override inline val one: Byte get() = 1 + public override inline val one: Byte + get() = 1 - override fun number(value: Number): Byte = value.toByte() - override inline fun add(left: Byte, right: Byte): Byte = (left + right).toByte() - override inline fun multiply(left: Byte, right: Byte): Byte = (left * right).toByte() - override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte() + public override fun number(value: Number): Byte = value.toByte() + public override inline fun add(a: Byte, b: Byte): Byte = (a + b).toByte() + public override inline fun multiply(a: Byte, b: Byte): Byte = (a * b).toByte() + public override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte() - override inline fun Byte.unaryMinus(): Byte = (-this).toByte() - override inline fun Byte.plus(arg: Byte): Byte = (this + arg).toByte() - override inline fun Byte.minus(arg: Byte): Byte = (this - arg).toByte() - override inline fun Byte.times(arg: Byte): Byte = (this * arg).toByte() + public override inline fun Byte.unaryMinus(): Byte = (-this).toByte() + public override inline fun Byte.plus(b: Byte): Byte = (this + b).toByte() + public override inline fun Byte.minus(b: Byte): Byte = (this - b).toByte() + public override inline fun Byte.times(b: Byte): Byte = (this * b).toByte() } -public val Byte.Companion.algebra: ByteRing get() = ByteRing - /** * A field for [Double] without boxing. Does not produce appropriate ring element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object LongRing : Ring, Norm, NumericAlgebra { - override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::LongBuffer) + public override inline val zero: Long + get() = 0L - override inline val zero: Long get() = 0L - override inline val one: Long get() = 1L + public override inline val one: Long + get() = 1L - override fun number(value: Number): Long = value.toLong() - override inline fun add(left: Long, right: Long): Long = left + right - override inline fun multiply(left: Long, right: Long): Long = left * right - override fun norm(arg: Long): Long = abs(arg) + public override fun number(value: Number): Long = value.toLong() + public override inline fun add(a: Long, b: Long): Long = a + b + public override inline fun multiply(a: Long, b: Long): Long = a * b + public override fun norm(arg: Long): Long = abs(arg) - override inline fun Long.unaryMinus(): Long = (-this) - override inline fun Long.plus(arg: Long): Long = (this + arg) - override inline fun Long.minus(arg: Long): Long = (this - arg) - override inline fun Long.times(arg: Long): Long = (this * arg) + public override inline fun Long.unaryMinus(): Long = (-this) + public override inline fun Long.plus(b: Long): Long = (this + b) + public override inline fun Long.minus(b: Long): Long = (this - b) + public override inline fun Long.times(b: Long): Long = (this * b) } - -public val Long.Companion.algebra: LongRing get() = LongRing diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt deleted file mode 100644 index 8e81dd941..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.structures - -/** - * [MutableBuffer] implementation over [Array]. - * - * @param T the type of elements contained in the buffer. - * @property array The underlying array. - */ -public class ArrayBuffer(internal val array: Array) : MutableBuffer { - // Can't inline because array is invariant - override val size: Int get() = array.size - - override operator fun get(index: Int): T = array[index] - - override operator fun set(index: Int, value: T) { - array[index] = value - } - - override operator fun iterator(): Iterator = array.iterator() - override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf()) - - override fun toString(): String = Buffer.toString(this) -} - - -/** - * Returns an [ArrayBuffer] that wraps the original array. - */ -public fun Array.asBuffer(): ArrayBuffer = ArrayBuffer(this) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index cef8d1d4d..d187beab1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -1,12 +1,10 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures -import space.kscience.kmath.operations.WithSize -import space.kscience.kmath.operations.asSequence import kotlin.jvm.JvmInline import kotlin.reflect.KClass @@ -15,34 +13,14 @@ import kotlin.reflect.KClass * * @param T the type of buffer. */ -public fun interface BufferFactory { - public operator fun invoke(size: Int, builder: (Int) -> T): Buffer - - public companion object{ - public inline fun auto(): BufferFactory = - BufferFactory(Buffer.Companion::auto) - - public fun boxing(): BufferFactory = - BufferFactory(Buffer.Companion::boxing) - } -} +public typealias BufferFactory = (Int, (Int) -> T) -> Buffer /** * Function that produces [MutableBuffer] from its size and function that supplies values. * * @param T the type of buffer. */ -public fun interface MutableBufferFactory : BufferFactory { - override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer - - public companion object { - public inline fun auto(): MutableBufferFactory = - MutableBufferFactory(MutableBuffer.Companion::auto) - - public fun boxing(): MutableBufferFactory = - MutableBufferFactory(MutableBuffer.Companion::boxing) - } -} +public typealias MutableBufferFactory = (Int, (Int) -> T) -> MutableBuffer /** * A generic read-only random-access structure for both primitives and objects. @@ -51,11 +29,11 @@ public fun interface MutableBufferFactory : BufferFactory { * * @param T the type of elements contained in the buffer. */ -public interface Buffer : WithSize { +public interface Buffer { /** * The size of this buffer. */ - override val size: Int + public val size: Int /** * Gets element at given index. @@ -65,15 +43,9 @@ public interface Buffer : WithSize { /** * Iterates over all elements. */ - public operator fun iterator(): Iterator = indices.asSequence().map(::get).iterator() - - override fun toString(): String + public operator fun iterator(): Iterator public companion object { - - public fun toString(buffer: Buffer<*>): String = - buffer.asSequence().joinToString(prefix = "[", separator = ", ", postfix = "]") - /** * Check the element-by-element match of content of two buffers. */ @@ -115,6 +87,7 @@ public interface Buffer : WithSize { * * The [size] is specified, and each element is calculated by calling the specified [initializer] function. */ + @Suppress("UNCHECKED_CAST") public inline fun auto(size: Int, initializer: (Int) -> T): Buffer = auto(T::class, size, initializer) } @@ -123,25 +96,172 @@ public interface Buffer : WithSize { /** * Returns an [IntRange] of the valid indices for this [Buffer]. */ -public val Buffer.indices: IntRange get() = 0 until size - -public operator fun Buffer.get(index: UInt): T = get(index.toInt()) +public val Buffer<*>.indices: IntRange get() = 0 until size /** - * if index is in range of buffer, return the value. Otherwise, return null. + * A generic mutable random-access structure for both primitives and objects. + * + * @param T the type of elements contained in the buffer. */ -public fun Buffer.getOrNull(index: Int): T? = if (index in indices) get(index) else null +public interface MutableBuffer : Buffer { + /** + * Sets the array element at the specified [index] to the specified [value]. + */ + public operator fun set(index: Int, value: T) -public fun Buffer.first(): T { - require(size > 0) { "Can't get the first element of empty buffer" } - return get(0) + /** + * Returns a shallow copy of the buffer. + */ + public fun copy(): MutableBuffer + + public companion object { + /** + * Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer = + DoubleBuffer(size, initializer) + + /** + * Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer = + ShortBuffer(size, initializer) + + /** + * Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer = + IntBuffer(size, initializer) + + /** + * Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer = + LongBuffer(size, initializer) + + + /** + * Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer = + FloatBuffer(size, initializer) + + + /** + * Create a boxing mutable buffer of given type + */ + public inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = + MutableListBuffer(MutableList(size, initializer)) + + /** + * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used + * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. + * + * The [size] is specified, and each element is calculated by calling the specified [initializer] function. + */ + @Suppress("UNCHECKED_CAST") + public inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer = + when (type) { + Double::class -> double(size) { initializer(it) as Double } as MutableBuffer + Short::class -> short(size) { initializer(it) as Short } as MutableBuffer + Int::class -> int(size) { initializer(it) as Int } as MutableBuffer + Float::class -> float(size) { initializer(it) as Float } as MutableBuffer + Long::class -> long(size) { initializer(it) as Long } as MutableBuffer + else -> boxing(size, initializer) + } + + /** + * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used + * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. + * + * The [size] is specified, and each element is calculated by calling the specified [initializer] function. + */ + @Suppress("UNCHECKED_CAST") + public inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = + auto(T::class, size, initializer) + } } -public fun Buffer.last(): T { - require(size > 0) { "Can't get the last element of empty buffer" } - return get(size - 1) +/** + * [Buffer] implementation over [List]. + * + * @param T the type of elements contained in the buffer. + * @property list The underlying list. + */ +public class ListBuffer(public val list: List) : Buffer { + + public constructor(size: Int, initializer: (Int) -> T) : this(List(size, initializer)) + + override val size: Int get() = list.size + + override operator fun get(index: Int): T = list[index] + override operator fun iterator(): Iterator = list.iterator() } +/** + * Returns an [ListBuffer] that wraps the original list. + */ +public fun List.asBuffer(): ListBuffer = ListBuffer(this) + +/** + * [MutableBuffer] implementation over [MutableList]. + * + * @param T the type of elements contained in the buffer. + * @property list The underlying list. + */ +@JvmInline +public value class MutableListBuffer(public val list: MutableList) : MutableBuffer { + + public constructor(size: Int, initializer: (Int) -> T) : this(MutableList(size, initializer)) + + override val size: Int get() = list.size + + override operator fun get(index: Int): T = list[index] + + override operator fun set(index: Int, value: T) { + list[index] = value + } + + override operator fun iterator(): Iterator = list.iterator() + override fun copy(): MutableBuffer = MutableListBuffer(ArrayList(list)) +} + +/** + * Returns an [ListBuffer] that wraps the original list. + */ +public fun MutableList.asMutableBuffer(): MutableListBuffer = MutableListBuffer(this) + +/** + * [MutableBuffer] implementation over [Array]. + * + * @param T the type of elements contained in the buffer. + * @property array The underlying array. + */ +public class ArrayBuffer(internal val array: Array) : MutableBuffer { + // Can't inline because array is invariant + override val size: Int get() = array.size + + override operator fun get(index: Int): T = array[index] + + override operator fun set(index: Int, value: T) { + array[index] = value + } + + override operator fun iterator(): Iterator = array.iterator() + override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf()) +} + + +/** + * Returns an [ArrayBuffer] that wraps the original array. + */ +public fun Array.asBuffer(): ArrayBuffer = ArrayBuffer(this) + /** * Immutable wrapper for [MutableBuffer]. * @@ -163,15 +283,13 @@ public value class ReadOnlyBuffer(public val buffer: MutableBuffer) : Buff * * @param T the type of elements provided by the buffer. */ -public class VirtualBuffer(override val size: Int, private val generator: (Int) -> T) : Buffer { +public class VirtualBuffer(override val size: Int, private val generator: (Int) -> T) : Buffer { override operator fun get(index: Int): T { if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index") return generator(index) } override operator fun iterator(): Iterator = (0 until size).asSequence().map(generator).iterator() - - override fun toString(): String = Buffer.toString(this) } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt index 48f3e919b..352c75956 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt @@ -1,40 +1,43 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.DefaultStrides +import space.kscience.kmath.nd.Structure2D +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.as2D /** * A context that allows to operate on a [MutableBuffer] as on 2d array */ -internal class BufferAccessor2D( - val rowNum: Int, - val colNum: Int, +internal class BufferAccessor2D( + public val rowNum: Int, + public val colNum: Int, val factory: MutableBufferFactory, ) { - operator fun Buffer.get(i: Int, j: Int): T = get(i * colNum + j) + public operator fun Buffer.get(i: Int, j: Int): T = get(i * colNum + j) - operator fun MutableBuffer.set(i: Int, j: Int, value: T) { + public operator fun MutableBuffer.set(i: Int, j: Int, value: T) { set(i * colNum + j, value) } - inline fun create(crossinline init: (i: Int, j: Int) -> T): MutableBuffer = + public inline fun create(crossinline init: (i: Int, j: Int) -> T): MutableBuffer = factory(rowNum * colNum) { offset -> init(offset / colNum, offset % colNum) } - fun create(mat: Structure2D): MutableBuffer = create { i, j -> mat[i, j] } + public fun create(mat: Structure2D): MutableBuffer = create { i, j -> mat[i, j] } //TODO optimize wrapper - fun MutableBuffer.collect(): Structure2D = StructureND.buffered( - ColumnStrides(ShapeND(rowNum, colNum)), + public fun MutableBuffer.collect(): Structure2D = StructureND.buffered( + DefaultStrides(intArrayOf(rowNum, colNum)), factory ) { (i, j) -> get(i, j) }.as2D() - inner class Row(val buffer: MutableBuffer, val rowIndex: Int) : MutableBuffer { + public inner class Row(public val buffer: MutableBuffer, public val rowIndex: Int) : MutableBuffer { override val size: Int get() = colNum override operator fun get(index: Int): T = buffer[rowIndex, index] @@ -46,12 +49,10 @@ internal class BufferAccessor2D( override fun copy(): MutableBuffer = factory(colNum) { get(it) } override operator fun iterator(): Iterator = (0 until colNum).map(::get).iterator() - override fun toString(): String = Buffer.toString(this) - } /** * Get row */ - fun MutableBuffer.row(i: Int): Row = Row(this, i) + public fun MutableBuffer.row(i: Int): Row = Row(this, i) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt deleted file mode 100644 index 02fd2600d..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt +++ /dev/null @@ -1,192 +0,0 @@ -package space.kscience.kmath.structures - -import space.kscience.kmath.UnstableKMathAPI - -/** - * A buffer that wraps an original buffer - */ -public interface BufferView : Buffer { - public val origin: Buffer - - /** - * Get the index in [origin] buffer from index in this buffer. - * Return -1 if element not present in the original buffer - * This method should be used internally to optimize non-boxing access. - */ - @UnstableKMathAPI - public fun originIndex(index: Int): Int - - @OptIn(UnstableKMathAPI::class) - override fun get(index: Int): T = origin[originIndex(index)] -} - -/** - * A zero-copy buffer that "sees" only part of original buffer. Slice can't go beyond original buffer borders. - */ -public class BufferSlice( - override val origin: Buffer, - public val offset: Int = 0, - override val size: Int, -) : BufferView { - - init { - require(size > 0) { "Size must be positive" } - require(offset + size <= origin.size) { - "End of buffer ${offset + size} is beyond the end of origin buffer size ${origin.size}" - } - } - - override fun get(index: Int): T = if (index >= size) { - throw IndexOutOfBoundsException("$index is out of ${0 until size} rage") - } else { - origin[index + offset] - } - - override fun iterator(): Iterator = - (offset until (offset + size)).asSequence().map { origin[it] }.iterator() - - @UnstableKMathAPI - override fun originIndex(index: Int): Int = if (index >= size) -1 else index - offset - - override fun toString(): String = "$origin[$offset..${offset + size}" -} - -/** - * An expanded buffer that could include the whole initial buffer or its part and fills all space beyond it borders with [defaultValue]. - * - * The [offset] parameter shows the shift of expanded buffer start relative to origin start and could be both positive and negative. - */ -public class BufferExpanded( - override val origin: Buffer, - private val defaultValue: T, - public val offset: Int = 0, - override val size: Int = origin.size, -) : BufferView { - - init { - require(size > 0) { "Size must be positive" } - } - - override fun get(index: Int): T = when (index) { - !in 0 until size -> throw IndexOutOfBoundsException("Index $index is not in $indices") - in -offset until origin.size - offset -> origin[index + offset] - else -> defaultValue - } - - @UnstableKMathAPI - override fun originIndex(index: Int): Int = if (index in -offset until origin.size - offset) index + offset else -1 - - override fun toString(): String = "$origin[$offset..${offset + size}]" -} - -/** - * Zero-copy select a slice inside the original buffer - */ -public fun Buffer.slice(range: IntRange): BufferView = if (this is BufferSlice) { - BufferSlice( - origin, - this.offset + range.first, - (range.last - range.first) + 1 - ) -} else { - BufferSlice( - this, - range.first, - (range.last - range.first) + 1 - ) -} - -/** - * Resize original buffer to a given range using given [range], filling additional segments with [defaultValue]. - * Range left border could be negative to designate adding new blank segment to the beginning of the buffer - */ -public fun Buffer.expand( - range: IntRange, - defaultValue: T, -): BufferView = if (range.first >= 0 && range.last < size) { - BufferSlice( - this, - range.first, - (range.last - range.first) + 1 - ) -} else { - BufferExpanded( - this, - defaultValue, - range.first, - (range.last - range.first) + 1 - ) -} - -/** - * A [BufferView] that overrides indexing of the original buffer - */ -public class PermutedBuffer( - override val origin: Buffer, - private val permutations: IntArray, -) : BufferView { - init { - permutations.forEach { index -> - if (index !in origin.indices) { - throw IndexOutOfBoundsException("Index $index is not in ${origin.indices}") - } - } - } - - override val size: Int get() = permutations.size - - override fun get(index: Int): T = origin[permutations[index]] - - override fun iterator(): Iterator = permutations.asSequence().map { origin[it] }.iterator() - - @UnstableKMathAPI - override fun originIndex(index: Int): Int = if (index in permutations.indices) permutations[index] else -1 - - override fun toString(): String = Buffer.toString(this) -} - -/** - * Created a permuted view of given buffer using provided [indices] - */ -public fun Buffer.permute(indices: IntArray): PermutedBuffer = - PermutedBuffer(this, indices) - -/** - * A [BufferView] that overrides indexing of the original buffer - */ -public class PermutedMutableBuffer( - override val origin: MutableBuffer, - private val permutations: IntArray, -) : BufferView, MutableBuffer { - init { - permutations.forEach { index -> - if (index !in origin.indices) { - throw IndexOutOfBoundsException("Index $index is not in ${origin.indices}") - } - } - } - - override val size: Int get() = permutations.size - - override fun get(index: Int): T = origin[permutations[index]] - - override fun set(index: Int, value: T) { - origin[permutations[index]] = value - } - - override fun copy(): MutableBuffer = PermutedMutableBuffer(origin.copy(), permutations) - //TODO Probably could be optimized - - override fun iterator(): Iterator = permutations.asSequence().map { origin[it] }.iterator() - - @UnstableKMathAPI - override fun originIndex(index: Int): Int = if (index in permutations.indices) permutations[index] else -1 - - override fun toString(): String = Buffer.toString(this) -} - -/** - * Created a permuted mutable view of given buffer using provided [indices] - */ -public fun MutableBuffer.permute(indices: IntArray): PermutedMutableBuffer = - PermutedMutableBuffer(this, indices) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt deleted file mode 100644 index 2be17c5e4..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.structures - -import kotlin.jvm.JvmInline - -/** - * Specialized [MutableBuffer] implementation over [ByteArray]. - * - * @property array the underlying array. - */ -@JvmInline -public value class ByteBuffer(public val array: ByteArray) : MutableBuffer { - override val size: Int get() = array.size - - override operator fun get(index: Int): Byte = array[index] - - override operator fun set(index: Int, value: Byte) { - array[index] = value - } - - override operator fun iterator(): ByteIterator = array.iterator() - override fun copy(): MutableBuffer = ByteBuffer(array.copyOf()) -} - -/** - * Creates a new [ByteBuffer] with the specified [size], where each element is calculated by calling the specified - * [init] function. - * - * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for a buffer element given its index. - */ -public inline fun ByteBuffer(size: Int, init: (Int) -> Byte): ByteBuffer = ByteBuffer(ByteArray(size) { init(it) }) - -/** - * Returns a new [ByteBuffer] of given elements. - */ -public fun ByteBuffer(vararg bytes: Byte): ByteBuffer = ByteBuffer(bytes) - -/** - * Returns a new [ByteArray] containing all the elements of this [Buffer]. - */ -public fun Buffer.toByteArray(): ByteArray = when (this) { - is ByteBuffer -> array.copyOf() - else -> ByteArray(size, ::get) -} - -/** - * Returns [ByteBuffer] over this array. - * - * @receiver the array. - * @return the new buffer. - */ -public fun ByteArray.asBuffer(): ByteBuffer = ByteBuffer(this) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt index 1696d5055..b4ef37598 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt @@ -1,11 +1,10 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures -import space.kscience.kmath.operations.BufferTransform import kotlin.jvm.JvmInline /** @@ -14,7 +13,7 @@ import kotlin.jvm.JvmInline * @property array the underlying array. */ @JvmInline -public value class DoubleBuffer(public val array: DoubleArray) : PrimitiveBuffer { +public value class DoubleBuffer(public val array: DoubleArray) : MutableBuffer { override val size: Int get() = array.size override operator fun get(index: Int): Double = array[index] @@ -26,12 +25,6 @@ public value class DoubleBuffer(public val array: DoubleArray) : PrimitiveBuffer override operator fun iterator(): DoubleIterator = array.iterator() override fun copy(): DoubleBuffer = DoubleBuffer(array.copyOf()) - - override fun toString(): String = Buffer.toString(this) - - public companion object { - public fun zero(size: Int): DoubleBuffer = DoubleArray(size).asBuffer() - } } /** @@ -39,10 +32,9 @@ public value class DoubleBuffer(public val array: DoubleArray) : PrimitiveBuffer * [init] function. * * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for a buffer element given its index. + * It should return the value for an buffer element given its index. */ -public inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = - DoubleBuffer(DoubleArray(size) { init(it) }) +public inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = DoubleBuffer(DoubleArray(size) { init(it) }) /** * Returns a new [DoubleBuffer] of given elements. @@ -50,19 +42,16 @@ public inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = public fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(doubles) /** - * Returns a new [DoubleArray] containing all the elements of this [Buffer]. + * Simplified [DoubleBuffer] to array comparison */ -public fun Buffer.toDoubleArray(): DoubleArray = when (this) { - is DoubleBuffer -> array - else -> DoubleArray(size, ::get) -} +public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles) /** - * Represent this buffer as [DoubleBuffer]. Does not guarantee that changes in the original buffer are reflected on this buffer. + * Returns a new [DoubleArray] containing all of the elements of this [Buffer]. */ -public fun Buffer.toDoubleBuffer(): DoubleBuffer = when (this) { - is DoubleBuffer -> this - else -> DoubleArray(size, ::get).asBuffer() +public fun Buffer.toDoubleArray(): DoubleArray = when (this) { + is DoubleBuffer -> array.copyOf() + else -> DoubleArray(size, ::get) } /** @@ -72,10 +61,3 @@ public fun Buffer.toDoubleBuffer(): DoubleBuffer = when (this) { * @return the new buffer. */ public fun DoubleArray.asBuffer(): DoubleBuffer = DoubleBuffer(this) - - -public fun interface DoubleBufferTransform : BufferTransform { - public fun transform(arg: DoubleBuffer): DoubleBuffer - - override fun transform(arg: Buffer): DoubleBuffer = arg.toDoubleBuffer() -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt new file mode 100644 index 000000000..34b5e373b --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt @@ -0,0 +1,277 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.structures + +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.ExtendedFieldOperations +import kotlin.math.* + +/** + * [ExtendedFieldOperations] over [DoubleBuffer]. + */ +public object DoubleBufferFieldOperations : ExtendedFieldOperations> { + override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { + DoubleBuffer(size) { -array[it] } + } else { + DoubleBuffer(size) { -get(it) } + } + + public override fun add(a: Buffer, b: Buffer): DoubleBuffer { + require(b.size == a.size) { + "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " + } + + return if (a is DoubleBuffer && b is DoubleBuffer) { + val aArray = a.array + val bArray = b.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] }) + } else DoubleBuffer(DoubleArray(a.size) { a[it] + b[it] }) + } +// +// public override fun multiply(a: Buffer, k: Number): RealBuffer { +// val kValue = k.toDouble() +// +// return if (a is RealBuffer) { +// val aArray = a.array +// RealBuffer(DoubleArray(a.size) { aArray[it] * kValue }) +// } else RealBuffer(DoubleArray(a.size) { a[it] * kValue }) +// } +// +// public override fun divide(a: Buffer, k: Number): RealBuffer { +// val kValue = k.toDouble() +// +// return if (a is RealBuffer) { +// val aArray = a.array +// RealBuffer(DoubleArray(a.size) { aArray[it] / kValue }) +// } else RealBuffer(DoubleArray(a.size) { a[it] / kValue }) +// } + + public override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { + require(b.size == a.size) { + "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " + } + + return if (a is DoubleBuffer && b is DoubleBuffer) { + val aArray = a.array + val bArray = b.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] }) + } else + DoubleBuffer(DoubleArray(a.size) { a[it] * b[it] }) + } + + public override fun divide(a: Buffer, b: Buffer): DoubleBuffer { + require(b.size == a.size) { + "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " + } + + return if (a is DoubleBuffer && b is DoubleBuffer) { + val aArray = a.array + val bArray = b.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] }) + } else DoubleBuffer(DoubleArray(a.size) { a[it] / b[it] }) + } + + public override fun sin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) }) + } else DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) }) + + public override fun cos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) }) + } else DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) }) + + public override fun tan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { tan(array[it]) }) + } else DoubleBuffer(DoubleArray(arg.size) { tan(arg[it]) }) + + public override fun asin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { asin(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { asin(arg[it]) }) + + public override fun acos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { acos(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { acos(arg[it]) }) + + public override fun atan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { atan(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { atan(arg[it]) }) + + public override fun sinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { sinh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { sinh(arg[it]) }) + + public override fun cosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { cosh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { cosh(arg[it]) }) + + public override fun tanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { tanh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { tanh(arg[it]) }) + + public override fun asinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { asinh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { asinh(arg[it]) }) + + public override fun acosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { acosh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { acosh(arg[it]) }) + + public override fun atanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { atanh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { atanh(arg[it]) }) + + public override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) }) + } else + DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) }) + + public override fun exp(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) }) + } else DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) }) + + public override fun ln(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) }) +} + +/** + * [ExtendedField] over [DoubleBuffer]. + * + * @property size the size of buffers to operate on. + */ +public class DoubleBufferField(public val size: Int) : ExtendedField> { + public override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } + public override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } + + override fun number(value: Number): Buffer = DoubleBuffer(size) { value.toDouble() } + + override fun Buffer.unaryMinus(): Buffer = DoubleBufferFieldOperations.run { + -this@unaryMinus + } + + public override fun add(a: Buffer, b: Buffer): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return DoubleBufferFieldOperations.add(a, b) + } + + public override fun scale(a: Buffer, value: Double): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + + return if (a is DoubleBuffer) { + val aArray = a.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] * value }) + } else DoubleBuffer(DoubleArray(a.size) { a[it] * value }) + } + + public override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return DoubleBufferFieldOperations.multiply(a, b) + } + + public override fun divide(a: Buffer, b: Buffer): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return DoubleBufferFieldOperations.divide(a, b) + } + + public override fun sin(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.sin(arg) + } + + public override fun cos(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.cos(arg) + } + + public override fun tan(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.tan(arg) + } + + public override fun asin(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.asin(arg) + } + + public override fun acos(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.acos(arg) + } + + public override fun atan(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.atan(arg) + } + + public override fun sinh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.sinh(arg) + } + + public override fun cosh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.cosh(arg) + } + + public override fun tanh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.tanh(arg) + } + + public override fun asinh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.asinh(arg) + } + + public override fun acosh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.acosh(arg) + } + + public override fun atanh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.atanh(arg) + } + + public override fun power(arg: Buffer, pow: Number): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.power(arg, pow) + } + + public override fun exp(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.exp(arg) + } + + public override fun ln(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.ln(arg) + } +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt index d99e02996..a63f452f5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -37,7 +37,7 @@ public enum class ValueFlag(public val mask: Byte) { /** * A buffer with flagged values. */ -public interface FlaggedBuffer : Buffer { +public interface FlaggedBuffer : Buffer { public fun getFlag(index: Int): Byte } @@ -51,12 +51,10 @@ public fun FlaggedBuffer<*>.hasFlag(index: Int, flag: ValueFlag): Boolean = (get public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, ValueFlag.MISSING) /** - * A [Double] buffer that supports flags for each value like `NaN` or Missing. + * A real buffer which supports flags for each value like NaN or Missing */ -public class FlaggedDoubleBuffer( - public val values: DoubleArray, - public val flags: ByteArray -) : FlaggedBuffer, Buffer { +public class FlaggedDoubleBuffer(public val values: DoubleArray, public val flags: ByteArray) : FlaggedBuffer, + Buffer { init { require(values.size == flags.size) { "Values and flags must have the same dimensions" } } @@ -70,8 +68,6 @@ public class FlaggedDoubleBuffer( override operator fun iterator(): Iterator = values.indices.asSequence().map { if (isValid(it)) values[it] else null }.iterator() - - override fun toString(): String = Buffer.toString(this) } public inline fun FlaggedDoubleBuffer.forEachValid(block: (Double) -> Unit) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt index f1533ee3a..58b7c6aea 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -14,7 +14,7 @@ import kotlin.jvm.JvmInline * @author Iaroslav Postovalov */ @JvmInline -public value class FloatBuffer(public val array: FloatArray) : PrimitiveBuffer { +public value class FloatBuffer(public val array: FloatArray) : MutableBuffer { override val size: Int get() = array.size override operator fun get(index: Int): Float = array[index] @@ -34,7 +34,7 @@ public value class FloatBuffer(public val array: FloatArray) : PrimitiveBuffer Float): FloatBuffer = FloatBuffer(FloatArray(size) { init(it) }) @@ -44,7 +44,7 @@ public inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer = Fl public fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats) /** - * Returns a new [FloatArray] containing all the elements of this [Buffer]. + * Returns a new [FloatArray] containing all of the elements of this [Buffer]. */ public fun Buffer.toFloatArray(): FloatArray = when (this) { is FloatBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt index 0de7119b1..57b6cfde3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -13,7 +13,7 @@ import kotlin.jvm.JvmInline * @property array the underlying array. */ @JvmInline -public value class IntBuffer(public val array: IntArray) : PrimitiveBuffer { +public value class IntBuffer(public val array: IntArray) : MutableBuffer { override val size: Int get() = array.size override operator fun get(index: Int): Int = array[index] @@ -24,7 +24,8 @@ public value class IntBuffer(public val array: IntArray) : PrimitiveBuffer override operator fun iterator(): IntIterator = array.iterator() - override fun copy(): IntBuffer = IntBuffer(array.copyOf()) + override fun copy(): MutableBuffer = + IntBuffer(array.copyOf()) } /** @@ -32,7 +33,7 @@ public value class IntBuffer(public val array: IntArray) : PrimitiveBuffer * [init] function. * * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for a buffer element given its index. + * It should return the value for an buffer element given its index. */ public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffer(IntArray(size) { init(it) }) @@ -42,7 +43,7 @@ public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffe public fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints) /** - * Returns a new [IntArray] containing all the elements of this [Buffer]. + * Returns a new [IntArray] containing all of the elements of this [Buffer]. */ public fun Buffer.toIntArray(): IntArray = when (this) { is IntBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt deleted file mode 100644 index fbc9a489b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.structures - -import kotlin.jvm.JvmInline - -/** - * [Buffer] implementation over [List]. - * - * @param T the type of elements contained in the buffer. - * @property list The underlying list. - */ -public class ListBuffer(public val list: List) : Buffer { - - public constructor(size: Int, initializer: (Int) -> T) : this(List(size, initializer)) - - override val size: Int get() = list.size - - override operator fun get(index: Int): T = list[index] - override operator fun iterator(): Iterator = list.iterator() - - override fun toString(): String = Buffer.toString(this) -} - - -/** - * Returns an [ListBuffer] that wraps the original list. - */ -public fun List.asBuffer(): ListBuffer = ListBuffer(this) - -/** - * [MutableBuffer] implementation over [MutableList]. - * - * @param T the type of elements contained in the buffer. - * @property list The underlying list. - */ -@JvmInline -public value class MutableListBuffer(public val list: MutableList) : MutableBuffer { - - public constructor(size: Int, initializer: (Int) -> T) : this(MutableList(size, initializer)) - - override val size: Int get() = list.size - - override operator fun get(index: Int): T = list[index] - - override operator fun set(index: Int, value: T) { - list[index] = value - } - - override operator fun iterator(): Iterator = list.iterator() - override fun copy(): MutableBuffer = MutableListBuffer(ArrayList(list)) -} - -/** - * Returns an [MutableListBuffer] that wraps the original list. - */ -public fun MutableList.asMutableBuffer(): MutableListBuffer = MutableListBuffer(this) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt index 9f77fc9d8..57affa1c5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -13,7 +13,7 @@ import kotlin.jvm.JvmInline * @property array the underlying array. */ @JvmInline -public value class LongBuffer(public val array: LongArray) : PrimitiveBuffer { +public value class LongBuffer(public val array: LongArray) : MutableBuffer { override val size: Int get() = array.size override operator fun get(index: Int): Long = array[index] @@ -33,7 +33,7 @@ public value class LongBuffer(public val array: LongArray) : PrimitiveBuffer Long): LongBuffer = LongBuffer(LongArray(size) { init(it) }) @@ -43,7 +43,7 @@ public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongB public fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs) /** - * Returns a new [LongArray] containing all the elements of this [Buffer]. + * Returns a new [LongArray] containing all of the elements of this [Buffer]. */ public fun Buffer.toLongArray(): LongArray = when (this) { is LongBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt index cbfd6b9cd..8c98ab9c8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -17,10 +17,10 @@ import space.kscience.kmath.memory.* public open class MemoryBuffer(protected val memory: Memory, protected val spec: MemorySpec) : Buffer { override val size: Int get() = memory.size / spec.objectSize - override operator fun get(index: Int): T = memory.read { read(spec, spec.objectSize * index) } - override operator fun iterator(): Iterator = (0 until size).asSequence().map { get(it) }.iterator() + private val reader: MemoryReader = memory.reader() - override fun toString(): String = Buffer.toString(this) + override operator fun get(index: Int): T = reader.read(spec, spec.objectSize * index) + override operator fun iterator(): Iterator = (0 until size).asSequence().map { get(it) }.iterator() public companion object { public fun create(spec: MemorySpec, size: Int): MemoryBuffer = @@ -48,8 +48,8 @@ public class MutableMemoryBuffer(memory: Memory, spec: MemorySpec) : private val writer: MemoryWriter = memory.writer() - override operator fun set(index: Int, value: T): Unit = writer.write(spec, spec.objectSize * index, value) - override fun copy(): MutableBuffer = MutableMemoryBuffer(memory.copy(), spec) + public override operator fun set(index: Int, value: T): Unit = writer.write(spec, spec.objectSize * index, value) + public override fun copy(): MutableBuffer = MutableMemoryBuffer(memory.copy(), spec) public companion object { public fun create(spec: MemorySpec, size: Int): MutableMemoryBuffer = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt deleted file mode 100644 index c0bfc6ecc..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.structures - -import kotlin.reflect.KClass - -/** - * A generic mutable random-access structure for both primitives and objects. - * - * @param T the type of elements contained in the buffer. - */ -public interface MutableBuffer : Buffer { - /** - * Sets the array element at the specified [index] to the specified [value]. - */ - public operator fun set(index: Int, value: T) - - /** - * Returns a shallow copy of the buffer. - */ - public fun copy(): MutableBuffer - - public companion object { - /** - * Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer = - DoubleBuffer(size, initializer) - - /** - * Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer = - ShortBuffer(size, initializer) - - /** - * Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer = - IntBuffer(size, initializer) - - /** - * Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer = - LongBuffer(size, initializer) - - - /** - * Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer = - FloatBuffer(size, initializer) - - - /** - * Create a boxing mutable buffer of given type - */ - public inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = - MutableListBuffer(MutableList(size, initializer)) - - /** - * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used - * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer = - when (type) { - Double::class -> double(size) { initializer(it) as Double } as MutableBuffer - Short::class -> short(size) { initializer(it) as Short } as MutableBuffer - Int::class -> int(size) { initializer(it) as Int } as MutableBuffer - Float::class -> float(size) { initializer(it) as Float } as MutableBuffer - Long::class -> long(size) { initializer(it) as Long } as MutableBuffer - else -> boxing(size, initializer) - } - - /** - * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used - * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = - auto(T::class, size, initializer) - } -} - - -public sealed interface PrimitiveBuffer: MutableBuffer \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt index 7dbb2b58e..3d4c68b3c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -14,16 +14,16 @@ import kotlin.jvm.JvmInline */ @JvmInline public value class ShortBuffer(public val array: ShortArray) : MutableBuffer { - override val size: Int get() = array.size + public override val size: Int get() = array.size - override operator fun get(index: Int): Short = array[index] + public override operator fun get(index: Int): Short = array[index] - override operator fun set(index: Int, value: Short) { + public override operator fun set(index: Int, value: Short) { array[index] = value } - override operator fun iterator(): ShortIterator = array.iterator() - override fun copy(): MutableBuffer = ShortBuffer(array.copyOf()) + public override operator fun iterator(): ShortIterator = array.iterator() + public override fun copy(): MutableBuffer = ShortBuffer(array.copyOf()) } /** @@ -31,7 +31,7 @@ public value class ShortBuffer(public val array: ShortArray) : MutableBuffer Short): ShortBuffer = ShortBuffer(ShortArray(size) { init(it) }) @@ -41,7 +41,7 @@ public inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer = Sh public fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts) /** - * Returns a new [ShortArray] containing all the elements of this [Buffer]. + * Returns a new [ShortArray] containing all of the elements of this [Buffer]. */ public fun Buffer.toShortArray(): ShortArray = when (this) { is ShortBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt similarity index 50% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt index 6a7b6d836..1b89e7838 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt @@ -1,26 +1,21 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.operations +package space.kscience.kmath.structures -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.structures.* +import space.kscience.kmath.misc.UnstableKMathAPI /** - * Type alias for buffer transformations. + * Typealias for buffer transformations. */ -public fun interface BufferTransform { - public fun transform(arg: Buffer): Buffer -} +public typealias BufferTransform = (Buffer) -> Buffer -///** -// * Type alias for buffer transformations with suspend function. -// */ -//public fun interface SuspendBufferTransform{ -// public suspend fun transform(arg: Buffer): Buffer -//} +/** + * Typealias for buffer transformations with suspend function. + */ +public typealias SuspendBufferTransform = suspend (Buffer) -> Buffer /** @@ -61,78 +56,47 @@ public fun Buffer.toMutableList(): MutableList = when (this) { */ @UnstableKMathAPI public inline fun Buffer.toTypedArray(): Array = Array(size, ::get) -// -///** -// * Create a new buffer from this one with the given mapping function and using [Buffer.Companion.auto] buffer factory. -// */ -//public inline fun Buffer.map(block: (T) -> R): Buffer = -// Buffer.auto(size) { block(get(it)) } + +/** + * Create a new buffer from this one with the given mapping function and using [Buffer.Companion.auto] buffer factory. + */ +public inline fun Buffer.map(block: (T) -> R): Buffer = + Buffer.auto(size) { block(get(it)) } /** * Create a new buffer from this one with the given mapping function. * Provided [bufferFactory] is used to construct the new buffer. */ -public inline fun Buffer.mapToBuffer( +public fun Buffer.map( bufferFactory: BufferFactory, - crossinline block: (T) -> R, + block: (T) -> R, ): Buffer = bufferFactory(size) { block(get(it)) } /** - * Create a new buffer from this one with the given mapping (indexed) function. - * Provided [bufferFactory] is used to construct the new buffer. + * Create a new buffer from this one with the given indexed mapping function. + * Provided [BufferFactory] is used to construct the new buffer. */ -public inline fun Buffer.mapIndexedToBuffer( - bufferFactory: BufferFactory, +public inline fun Buffer.mapIndexed( + bufferFactory: BufferFactory = Buffer.Companion::auto, crossinline block: (index: Int, value: T) -> R, ): Buffer = bufferFactory(size) { block(it, get(it)) } -// -///** -// * Create a new buffer from this one with the given indexed mapping function. -// * Provided [BufferFactory] is used to construct the new buffer. -// */ -//public inline fun Buffer.mapIndexed( -// crossinline block: (index: Int, value: T) -> R, -//): Buffer = Buffer.auto(size) { block(it, get(it)) } /** * Fold given buffer according to [operation] */ -public inline fun Buffer.fold(initial: R, operation: (acc: R, T) -> R): R { - if (size == 0) return initial +public inline fun Buffer.fold(initial: R, operation: (acc: R, T) -> R): R { var accumulator = initial for (index in this.indices) accumulator = operation(accumulator, get(index)) return accumulator } -/** - * Fold given buffer according to indexed [operation] - */ -public inline fun Buffer.foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): R { - if (size == 0) return initial - var accumulator = initial - for (index in this.indices) accumulator = operation(index, accumulator, get(index)) - return accumulator -} - -/** - * Reduce a buffer from left to right according to [operation] - */ -public inline fun Buffer.reduce(operation: (left: T, value: T) -> T): T { - require(size > 0) { "Buffer must have elements" } - var current = get(0) - for (i in 1 until size) { - current = operation(current, get(i)) - } - return current -} - /** * Zip two buffers using given [transform]. */ @UnstableKMathAPI -public inline fun Buffer.combineToBuffer( +public inline fun Buffer.zip( other: Buffer, - bufferFactory: BufferFactory, + bufferFactory: BufferFactory = Buffer.Companion::auto, crossinline transform: (T1, T2) -> R, ): Buffer { require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt deleted file mode 100644 index 353892105..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt +++ /dev/null @@ -1,37 +0,0 @@ -package space.kscience.kmath.structures - -import space.kscience.kmath.UnstableKMathAPI - -/** - * Non-boxing access to primitive [Double] - */ -@UnstableKMathAPI -public fun Buffer.getDouble(index: Int): Double = if (this is BufferView) { - val originIndex = originIndex(index) - if (originIndex >= 0) { - origin.getDouble(originIndex) - } else { - get(index) - } -} else if (this is DoubleBuffer) { - array[index] -} else { - get(index) -} - -/** - * Non-boxing access to primitive [Int] - */ -@UnstableKMathAPI -public fun Buffer.getInt(index: Int): Int = if (this is BufferView) { - val originIndex = originIndex(index) - if (originIndex >= 0) { - origin.getInt(originIndex) - } else { - get(index) - } -} else if (this is IntBuffer) { - array[index] -} else { - get(index) -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/types.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/types.kt deleted file mode 100644 index 4ace17538..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/types.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.structures - - -public typealias Float32 = Float -public typealias Float64 = Double - -public typealias Int8 = Byte -public typealias Int16 = Short -public typealias Int32 = Int -public typealias Int64 = Long - -public typealias UInt8 = UByte -public typealias UInt16 = UShort -public typealias UInt32 = UInt -public typealias UInt64 = ULong \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt deleted file mode 100644 index 871119f48..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.expressions - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFails - -internal inline fun diff( - order: Int, - vararg parameters: Pair, - block: DSField.() -> Unit, -) { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - DSField(DoubleField, order, mapOf(*parameters)).block() -} - -internal class DSTest { - private val x by symbol - private val y by symbol - - @Test - fun dsAlgebraTest() { - diff(2, x to 1.0, y to 1.0) { - val x = bindSymbol(x)//by binding() - val y = bindSymbol("y") - val z = x * (-sin(x * y) + y) + 2.0 - println(z.derivative(x)) - println(z.derivative(y, x)) - assertEquals(z.derivative(x, y), z.derivative(y, x)) - // check improper order cause failure - assertFails { z.derivative(x, x, y) } - } - } - - @Test - fun dsExpressionTest() { - val f = DSFieldExpression(DoubleField) { - val x by binding - val y by binding - x.pow(2) + 2 * x * y + y.pow(2) + 1 - } - - assertEquals(10.0, f(x to 1.0, y to 2.0)) - assertEquals(6.0, f.derivative(x)(x to 1.0, y to 2.0)) - assertEquals(2.0, f.derivative(x, x)(x to 1.234, y to -2.0)) - assertEquals(2.0, f.derivative(x, y)(x to 1.0, y to 2.0)) - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt index def9f91a6..cf3a565bc 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt @@ -1,11 +1,13 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.expressions +import space.kscience.kmath.misc.symbol import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFails @@ -15,8 +17,8 @@ class ExpressionFieldTest { @Test fun testExpression() { - val expression = with(FunctionalExpressionField(DoubleField)) { - val x by binding + val expression = FunctionalExpressionField(DoubleField).invoke { + val x by binding() x * x + 2 * x + one } @@ -27,7 +29,7 @@ class ExpressionFieldTest { @Test fun separateContext() { fun FunctionalExpressionField.expression(): Expression { - val x by binding + val x by binding() return x * x + 2 * x + one } @@ -38,7 +40,7 @@ class ExpressionFieldTest { @Test fun valueExpression() { val expressionBuilder: FunctionalExpressionField.() -> Expression = { - val x by binding + val x by binding() x * x + 2 * x + one } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt deleted file mode 100644 index 83f00ce6c..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.operations.BooleanAlgebra -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import kotlin.test.Test -import kotlin.test.assertEquals - - -internal class InterpretTest { - @Test - fun interpretation() { - val expr = MstField { - x * 2.0 + number(2.0) / x - 16.0 - }.toExpression(DoubleField) - assertEquals(-10.69, expr(x to 2.2), 0.02) - } - - @Test - @UnstableKMathAPI - fun booleanAlgebra() { - val expr = MstLogicAlgebra { - x and const(true) - }.toExpression(BooleanAlgebra) - - assertEquals(true, expr(x to true)) - assertEquals(false, expr(x to false)) - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt index 1618296be..ab509650a 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt @@ -1,10 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.expressions +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.symbol import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.structures.Buffer @@ -17,7 +19,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -internal class SimpleAutoDiffTest { +class SimpleAutoDiffTest { fun dx( xBinding: Pair, diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt index 4d05f9043..ebbbbe392 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt @@ -1,19 +1,16 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.linear -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.algebra import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -@OptIn(PerformancePitfall::class) fun assertMatrixEquals(expected: StructureND, actual: StructureND) { assertTrue { StructureND.contentEquals(expected, actual) } } @@ -22,37 +19,39 @@ fun assertMatrixEquals(expected: StructureND, actual: StructureND = VirtualMatrix(6, 6) { row, col -> when { col == 0 -> .50 @@ -50,7 +46,7 @@ class MatrixTest { infix fun Matrix.pow(power: Int): Matrix { var res = this repeat(power - 1) { - res = res dot this@pow + res = LinearSpace.real.run { res dot this@pow } } return res } @@ -59,18 +55,19 @@ class MatrixTest { } @Test - fun test2DDot() = Double.algebra.linearSpace.run { + fun test2DDot() { val firstMatrix = StructureND.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D() val secondMatrix = StructureND.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D() + LinearSpace.real.run { // val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() } // val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() } - val result = firstMatrix dot secondMatrix - assertEquals(2, result.rowNum) - assertEquals(2, result.colNum) - assertEquals(8.0, result[0, 1]) - assertEquals(8.0, result[1, 0]) - assertEquals(14.0, result[1, 1]) - + val result = firstMatrix dot secondMatrix + assertEquals(2, result.rowNum) + assertEquals(2, result.colNum) + assertEquals(8.0, result[0, 1]) + assertEquals(8.0, result[1, 0]) + assertEquals(14.0, result[1, 1]) + } } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt similarity index 51% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt rename to kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt index 77ef07ea8..f2c7f1f90 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt @@ -1,8 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.misc - -public expect fun Long.toIntExact(): Int diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt index 811f2e87f..e5f3f337f 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt deleted file mode 100644 index dd97df1e8..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.misc - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.misc.PermSortTest.Platform.* -import space.kscience.kmath.structures.IntBuffer -import space.kscience.kmath.structures.asBuffer -import kotlin.random.Random -import kotlin.test.Test -import kotlin.test.assertContentEquals -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -@OptIn(UnstableKMathAPI::class) -class PermSortTest { - - private enum class Platform { - ANDROID, JVM, JS, NATIVE, WASM - } - - private val platforms = Platform.values().asBuffer() - - /** - * Permutation on empty buffer should immediately return an empty array. - */ - @Test - fun testOnEmptyBuffer() { - val emptyBuffer = IntBuffer(0) {it} - var permutations = emptyBuffer.indicesSorted() - assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") - permutations = emptyBuffer.indicesSortedDescending() - assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") - } - - @Test - fun testOnSingleValueBuffer() { - testPermutation(1) - } - - @Test - fun testOnSomeValues() { - testPermutation(10) - } - - @Test - fun testPermSortBy() { - val permutations = platforms.indicesSortedBy { it.name } - val expected = listOf(ANDROID, JS, JVM, NATIVE, WASM) - assertContentEquals(expected, permutations.map { platforms[it] }, "Ascending PermSort by name") - } - - @Test - fun testPermSortByDescending() { - val permutations = platforms.indicesSortedByDescending { it.name } - val expected = listOf(WASM, NATIVE, JVM, JS, ANDROID) - assertContentEquals(expected, permutations.map { platforms[it] }, "Descending PermSort by name") - } - - @Test - fun testPermSortWith() { - var permutations = platforms.indicesSortedWith { p1, p2 -> p1.name.length.compareTo(p2.name.length) } - val expected = listOf(JS, JVM, WASM, NATIVE, ANDROID) - assertContentEquals(expected, permutations.map { platforms[it] }, "PermSort using custom ascending comparator") - - permutations = platforms.indicesSortedWith(compareByDescending { it.name.length }) - assertContentEquals(expected.reversed(), permutations.map { platforms[it] }, "PermSort using custom descending comparator") - } - - private fun testPermutation(bufferSize: Int) { - - val seed = Random.nextLong() - println("Test randomization seed: $seed") - - val buffer = Random(seed).buffer(bufferSize) - val indices = buffer.indicesSorted() - - assertEquals(bufferSize, indices.size) - // Ensure no doublon is present in indices - assertEquals(indices.toSet().size, indices.size) - - for (i in 0 until (bufferSize-1)) { - val current = buffer[indices[i]] - val next = buffer[indices[i+1]] - assertTrue(current <= next, "Permutation indices not properly sorted") - } - - val descIndices = buffer.indicesSortedDescending() - assertEquals(bufferSize, descIndices.size) - // Ensure no doublon is present in indices - assertEquals(descIndices.toSet().size, descIndices.size) - - for (i in 0 until (bufferSize-1)) { - val current = buffer[descIndices[i]] - val next = buffer[descIndices[i+1]] - assertTrue(current >= next, "Permutation indices not properly sorted in descending order") - } - } - - private fun Random.buffer(size : Int) = IntBuffer(size) { nextInt() } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt deleted file mode 100644 index e909a2aea..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals - -class NdOperationsTest { - @Test - fun roll() { - val structure = DoubleField.ndAlgebra.structureND(5, 5) { index -> - index.sumOf { it.toDouble() } - } - - println(StructureND.toString(structure)) - - val rolled = structure.roll(0,-1) - - println(StructureND.toString(rolled)) - - assertEquals(4.0, rolled[0, 0]) - } - -} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/StridesTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/StridesTest.kt deleted file mode 100644 index e6335f652..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/StridesTest.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd - -import kotlin.test.Test - -class StridesTest { - @Test - fun checkRowBasedStrides() { - val strides = RowStrides(ShapeND(3, 3)) - var counter = 0 - for(i in 0..2){ - for(j in 0..2){ -// print(strides.offset(intArrayOf(i,j)).toString() + "\t") - require(strides.offset(intArrayOf(i,j)) == counter) - counter++ - } - println() - } - } - - @Test - fun checkColumnBasedStrides() { - val strides = ColumnStrides(ShapeND(3, 3)) - var counter = 0 - for(i in 0..2){ - for(j in 0..2){ -// print(strides.offset(intArrayOf(i,j)).toString() + "\t") - require(strides.offset(intArrayOf(j,i)) == counter) - counter++ - } - println() - } - } -} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt index 06a9ab439..5df89a385 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt @@ -1,13 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.operations -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.testutils.RingVerifier -import kotlin.math.pow import kotlin.test.Test import kotlin.test.assertEquals @@ -23,18 +21,6 @@ internal class BigIntAlgebraTest { assertEquals(res, 1_000_000.toBigInt()) } - @UnstableKMathAPI - @Test - fun testKBigIntegerRingPow() { - for (num in -5..5) - for (exponent in 0U..10U) - assertEquals( - num.toDouble().pow(exponent.toInt()).toLong().toBigInt(), - num.toBigInt().pow(exponent), - "$num ^ $exponent" - ) - } - @Test fun testKBigIntegerRingSum_100_000_000__100_000_000() { BigIntField { diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt index 786c68c70..eec3dc3bf 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt index 36f00dc75..a2832e531 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,43 +7,15 @@ package space.kscience.kmath.operations import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertNull @kotlin.ExperimentalUnsignedTypes class BigIntConversionsTest { - - @Test - fun testEmptyString() { - assertNull("".parseBigInteger()) - assertNull("+".parseBigInteger()) - assertNull("-".parseBigInteger()) - - assertNull("0x".parseBigInteger()) - assertNull("+0x".parseBigInteger()) - assertNull("-0x".parseBigInteger()) - - - assertNull("_".parseBigInteger()) - assertNull("+_".parseBigInteger()) - assertNull("-_".parseBigInteger()) - - assertNull("0x_".parseBigInteger()) - assertNull("+0x_".parseBigInteger()) - assertNull("-0x_".parseBigInteger()) - } - @Test fun testToString0x10() { val x = 0x10.toBigInt() assertEquals("0x10", x.toString()) } - @Test - fun testUnderscores() { - assertEquals("0x10", "0x_1_0_".parseBigInteger().toString()) - assertEquals("0xa", "_1_0_".parseBigInteger().toString()) - } - @Test fun testToString0x17ffffffd() { val x = 0x17ffffffdL.toBigInt() diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt index 8a6116605..ae34dbc04 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt @@ -1,16 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.operations -import kotlin.random.Random -import kotlin.random.nextUInt import kotlin.test.Test -import kotlin.test.assertContentEquals import kotlin.test.assertEquals -import kotlin.test.assertFalse @kotlin.ExperimentalUnsignedTypes class BigIntOperationsTest { @@ -154,17 +150,6 @@ class BigIntOperationsTest { assertEquals(prod, res) } - @Test - fun testKaratsuba() { - val random = Random(2222) - val x = uintArrayOf(12U, 345U) - val y = uintArrayOf(6U, 789U) - assertContentEquals(BigInt.naiveMultiplyMagnitudes(x, y), BigInt.karatsubaMultiplyMagnitudes(x, y)) - val x1 = UIntArray(Random.nextInt(100, 1000)) { random.nextUInt() } - val y1 = UIntArray(Random.nextInt(100, 1000)) { random.nextUInt() } - assertContentEquals(BigInt.naiveMultiplyMagnitudes(x1, y1), BigInt.karatsubaMultiplyMagnitudes(x1, y1)) - } - @Test fun test_shr_20() { val x = 20.toBigInt() @@ -398,12 +383,4 @@ class BigIntOperationsTest { return assertEquals(res, x % mod) } - - @Test - fun testNotEqualsOtherTypeInstanceButButNotFails() = assertFalse(0.toBigInt().equals("")) - - @Test - fun testIntAbsOverflow() { - assertEquals((-Int.MAX_VALUE.toLong().toBigInt() - 1.toBigInt()) * 2, 2.toBigInt() * Int.MIN_VALUE) - } } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt index 688daa7fe..c482dc978 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -18,16 +18,4 @@ internal class DoubleFieldTest { val sqrt = DoubleField { sqrt(25 * one) } assertEquals(5.0, sqrt) } - - @Test - fun testPow() = DoubleField { - val num = 5 * one - assertEquals(5.0, power(num, 1), 0.01) - assertEquals(25.0, power(num, 2), 0.01) - assertEquals(1.0, power(num, 0), 0.01) - assertEquals(0.2, power(num, -1), 0.01) - assertEquals(0.04, power(num, -2), 0.01) - assertEquals(0.0, power(num, Int.MIN_VALUE), 0.01) - assertEquals(1.0, power(zero, 0), 0.01) - } } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/BufferExpandedTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/BufferExpandedTest.kt deleted file mode 100644 index 04671e040..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/BufferExpandedTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -package space.kscience.kmath.structures - -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFails - -internal class BufferExpandedTest { - private val buffer = (0..100).toList().asBuffer() - - @Test - fun shrink(){ - val view = buffer.slice(20..30) - assertEquals(20, view[0]) - assertEquals(30, view[10]) - assertFails { view[11] } - } - - @Test - fun expandNegative(){ - val view: BufferView = buffer.expand(-20..113,0) - assertEquals(0,view[4]) - assertEquals(0,view[123]) - assertEquals(100, view[120]) - assertFails { view[-2] } - assertFails { view[134] } - } -} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt index 566145621..fdfa49d1d 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt @@ -1,14 +1,13 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures +import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.invoke import space.kscience.kmath.testutils.FieldVerifier import kotlin.test.Test @@ -17,12 +16,12 @@ import kotlin.test.assertEquals internal class NDFieldTest { @Test fun verify() { - (DoubleField.ndAlgebra(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } + (AlgebraND.real(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } } @Test fun testStrides() { - val ndArray = DoubleField.ndAlgebra.structureND(10, 10) { (it[0] + it[1]).toDouble() } + val ndArray = AlgebraND.real(10, 10).produce { (it[0] + it[1]).toDouble() } assertEquals(ndArray[5, 5], 10.0) } } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt index 993fb089f..99743d879 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt @@ -1,33 +1,24 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.nd.* import space.kscience.kmath.operations.Norm -import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.invoke -import kotlin.collections.component1 -import kotlin.collections.component2 import kotlin.math.abs import kotlin.math.pow import kotlin.test.Test import kotlin.test.assertEquals -@OptIn(PerformancePitfall::class) @Suppress("UNUSED_VARIABLE") class NumberNDFieldTest { - val algebra = DoubleField.ndAlgebra - val array1 = algebra.structureND(3, 3) { (i, j) -> (i + j).toDouble() } - val array2 = algebra.structureND(3, 3) { (i, j) -> (i - j).toDouble() } + val algebra = AlgebraND.real(3, 3) + val array1 = algebra.produce { (i, j) -> (i + j).toDouble() } + val array2 = algebra.produce { (i, j) -> (i - j).toDouble() } @Test fun testSum() { @@ -46,18 +37,17 @@ class NumberNDFieldTest { } @Test - fun testGeneration() = Double.algebra.linearSpace.run { + fun testGeneration() { - val array = buildMatrix(3, 3) { i, j -> + val array = LinearSpace.real.buildMatrix(3, 3) { i, j -> (i * 10 + j).toDouble() } - for (i in 0..2) { + for (i in 0..2) for (j in 0..2) { val expected = (i * 10 + j).toDouble() assertEquals(expected, array[i, j], "Error at index [$i, $j]") } - } } @Test @@ -80,21 +70,18 @@ class NumberNDFieldTest { @Test fun combineTest() { - algebra { - val division = zip(array1, array2) { l, r -> l / r } - } + val division = array1.combine(array2, Double::div) } - object L2Norm : Norm, Double> { - @OptIn(PerformancePitfall::class) - override fun norm(arg: StructureND): Double = + object L2Norm : Norm, Double> { + override fun norm(arg: StructureND): Double = kotlin.math.sqrt(arg.elements().sumOf { it.second.toDouble() }) } @Test fun testInternalContext() { algebra { - (DoubleField.ndAlgebra(array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } } + (AlgebraND.real(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } } } } } diff --git a/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt similarity index 88% rename from test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt rename to kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt index 261e74f5a..ddd8fc3ea 100644 --- a/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/test-utils/src/commonMain/kotlin/FieldVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt similarity index 93% rename from test-utils/src/commonMain/kotlin/FieldVerifier.kt rename to kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt index a03ca0a27..bd09ff449 100644 --- a/test-utils/src/commonMain/kotlin/FieldVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,7 +10,7 @@ import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals import kotlin.test.assertNotEquals -public class FieldVerifier>( +internal class FieldVerifier>( algebra: A, a: T, b: T, c: T, x: Number, ) : RingVerifier(algebra, a, b, c, x) { diff --git a/test-utils/src/commonMain/kotlin/RingVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt similarity index 93% rename from test-utils/src/commonMain/kotlin/RingVerifier.kt rename to kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt index c40075d93..885857f04 100644 --- a/test-utils/src/commonMain/kotlin/RingVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,7 +10,7 @@ import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals -public open class RingVerifier(algebra: A, a: T, b: T, c: T, x: Number) : +internal open class RingVerifier(algebra: A, a: T, b: T, c: T, x: Number) : SpaceVerifier(algebra, a, b, c, x) where A : Ring, A : ScaleOperations { override fun verify() { diff --git a/test-utils/src/commonMain/kotlin/SpaceVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt similarity index 90% rename from test-utils/src/commonMain/kotlin/SpaceVerifier.kt rename to kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt index 01c02997b..951197fc6 100644 --- a/test-utils/src/commonMain/kotlin/SpaceVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -11,12 +11,12 @@ import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals import kotlin.test.assertNotEquals -public open class SpaceVerifier( +internal open class SpaceVerifier( override val algebra: S, - public val a: T, - public val b: T, - public val c: T, - public val x: Number, + val a: T, + val b: T, + val c: T, + val x: Number, ) : AlgebraicVerifier> where S : Ring, S : ScaleOperations { override fun verify() { algebra { diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt deleted file mode 100644 index e52ea9298..000000000 --- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.misc - -public actual fun Long.toIntExact(): Int { - val i = toInt() - if (i.toLong() == this) throw ArithmeticException("integer overflow") - return i -} diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt deleted file mode 100644 index 3103f5168..000000000 --- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -/** - * Check if number is an integer - */ -public actual fun Number.isInteger(): Boolean = js("Number").isInteger(this) as Boolean \ No newline at end of file diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt deleted file mode 100644 index 3780ea1ae..000000000 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.misc - -public actual fun Long.toIntExact(): Int = Math.toIntExact(this) diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt index 584748bd7..9b46369bb 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -13,16 +13,16 @@ import java.math.MathContext * A field over [BigInteger]. */ public object JBigIntegerField : Ring, NumericAlgebra { - override val zero: BigInteger get() = BigInteger.ZERO + public override val zero: BigInteger get() = BigInteger.ZERO - override val one: BigInteger get() = BigInteger.ONE + public override val one: BigInteger get() = BigInteger.ONE - override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong()) - override fun add(left: BigInteger, right: BigInteger): BigInteger = left.add(right) - override operator fun BigInteger.minus(arg: BigInteger): BigInteger = subtract(arg) - override fun multiply(left: BigInteger, right: BigInteger): BigInteger = left.multiply(right) + public override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong()) + public override fun add(a: BigInteger, b: BigInteger): BigInteger = a.add(b) + public override operator fun BigInteger.minus(b: BigInteger): BigInteger = subtract(b) + public override fun multiply(a: BigInteger, b: BigInteger): BigInteger = a.multiply(b) - override operator fun BigInteger.unaryMinus(): BigInteger = negate() + public override operator fun BigInteger.unaryMinus(): BigInteger = negate() } /** @@ -33,24 +33,24 @@ public object JBigIntegerField : Ring, NumericAlgebra { public abstract class JBigDecimalFieldBase internal constructor( private val mathContext: MathContext = MathContext.DECIMAL64, ) : Field, PowerOperations, NumericAlgebra, ScaleOperations { - override val zero: BigDecimal + public override val zero: BigDecimal get() = BigDecimal.ZERO - override val one: BigDecimal + public override val one: BigDecimal get() = BigDecimal.ONE - override fun add(left: BigDecimal, right: BigDecimal): BigDecimal = left.add(right) - override operator fun BigDecimal.minus(arg: BigDecimal): BigDecimal = subtract(arg) - override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble()) + public override fun add(a: BigDecimal, b: BigDecimal): BigDecimal = a.add(b) + public override operator fun BigDecimal.minus(b: BigDecimal): BigDecimal = subtract(b) + public override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble()) - override fun scale(a: BigDecimal, value: Double): BigDecimal = + public override fun scale(a: BigDecimal, value: Double): BigDecimal = a.multiply(value.toBigDecimal(mathContext), mathContext) - override fun multiply(left: BigDecimal, right: BigDecimal): BigDecimal = left.multiply(right, mathContext) - override fun divide(left: BigDecimal, right: BigDecimal): BigDecimal = left.divide(right, mathContext) - override fun power(arg: BigDecimal, pow: Number): BigDecimal = arg.pow(pow.toInt(), mathContext) - override fun sqrt(arg: BigDecimal): BigDecimal = arg.sqrt(mathContext) - override operator fun BigDecimal.unaryMinus(): BigDecimal = negate(mathContext) + public override fun multiply(a: BigDecimal, b: BigDecimal): BigDecimal = a.multiply(b, mathContext) + public override fun divide(a: BigDecimal, b: BigDecimal): BigDecimal = a.divide(b, mathContext) + public override fun power(arg: BigDecimal, pow: Number): BigDecimal = arg.pow(pow.toInt(), mathContext) + public override fun sqrt(arg: BigDecimal): BigDecimal = arg.sqrt(mathContext) + public override operator fun BigDecimal.unaryMinus(): BigDecimal = negate(mathContext) } /** diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt deleted file mode 100644 index 9868daddf..000000000 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -/** - * Check if number is an integer - */ -public actual fun Number.isInteger(): Boolean = (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0) \ No newline at end of file diff --git a/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/misc/JBigTest.kt b/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/misc/JBigTest.kt deleted file mode 100644 index f7f8027e6..000000000 --- a/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/misc/JBigTest.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.misc - -import org.junit.jupiter.api.Test -import space.kscience.kmath.operations.JBigDecimalField -import kotlin.test.assertEquals -import kotlin.test.assertNotEquals - -class JBigTest { - - @Test - fun testExact() = with(JBigDecimalField) { - assertNotEquals(0.3, 0.1 + 0.2) - assertEquals(one * 0.3, one * 0.1 + one * 0.2) - } -} \ No newline at end of file diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt deleted file mode 100644 index e52ea9298..000000000 --- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.misc - -public actual fun Long.toIntExact(): Int { - val i = toInt() - if (i.toLong() == this) throw ArithmeticException("integer overflow") - return i -} diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt deleted file mode 100644 index 9868daddf..000000000 --- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -/** - * Check if number is an integer - */ -public actual fun Number.isInteger(): Boolean = (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0) \ No newline at end of file diff --git a/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt deleted file mode 100644 index e320f350e..000000000 --- a/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.misc - -public actual fun Long.toIntExact(): Int { - val i = toInt() - if (i.toLong() == this) throw ArithmeticException("integer overflow") - return i -} diff --git a/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt deleted file mode 100644 index 11c82bf9e..000000000 --- a/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.operations - -/** - * Check if number is an integer from platform point of view - */ -public actual fun Number.isInteger(): Boolean = - (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0) \ No newline at end of file diff --git a/kmath-coroutines/README.md b/kmath-coroutines/README.md deleted file mode 100644 index 21831e514..000000000 --- a/kmath-coroutines/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-coroutines - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-coroutines:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-coroutines:0.4.0-dev-1") -} -``` diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts index 1e901ca98..30f9ce1f9 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -1,19 +1,33 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity + plugins { - id("space.kscience.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") } -kscience { - jvm() - js() - native() +kotlin.sourceSets { + all { + with(languageSettings) { + useExperimentalAnnotation("kotlinx.coroutines.InternalCoroutinesApi") + useExperimentalAnnotation("kotlinx.coroutines.ExperimentalCoroutinesApi") + useExperimentalAnnotation("kotlinx.coroutines.FlowPreview") + } + } - dependencies { - api(project(":kmath-core")) - api(project(":kmath-complex")) - api(spclibs.kotlinx.coroutines.core) + commonMain { + dependencies { + api(project(":kmath-core")) + api(project(":kmath-complex")) + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}") + } } } readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + maturity = Maturity.EXPERIMENTAL } \ No newline at end of file diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt index 2e9a15eed..70849f942 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -32,9 +32,9 @@ public interface BlockingBufferChain : BlockingChain, BufferChain { public fun nextBufferBlocking(size: Int): Buffer - override fun nextBlocking(): T = nextBufferBlocking(1)[0] + public override fun nextBlocking(): T = nextBufferBlocking(1)[0] - override suspend fun nextBuffer(size: Int): Buffer = nextBufferBlocking(size) + public override suspend fun nextBuffer(size: Int): Buffer = nextBufferBlocking(size) override suspend fun fork(): BlockingBufferChain } diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt index 797d2db4a..526250cf0 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -15,7 +15,7 @@ public interface BlockingDoubleChain : BlockingBufferChain { /** * Returns an [DoubleArray] chunk of [size] values of [next]. */ - override fun nextBufferBlocking(size: Int): DoubleBuffer + public override fun nextBufferBlocking(size: Int): DoubleBuffer override suspend fun fork(): BlockingDoubleChain @@ -29,4 +29,4 @@ public fun BlockingDoubleChain.map(transform: (Double) -> Double): BlockingDoubl } override suspend fun fork(): BlockingDoubleChain = this@map.fork().map(transform) -} +} \ No newline at end of file diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt index a481156f2..ac0327d0b 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt index 977346e68..b29165e32 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,11 +10,10 @@ import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.flow import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import space.kscience.kmath.UnstableKMathAPI /** * A not-necessary-Markov chain of some type - * @param T the chain element type + * @param T - the chain element type */ public interface Chain : Flow { /** @@ -23,7 +22,7 @@ public interface Chain : Flow { public suspend fun next(): T /** - * Create a copy of current chain state. Consuming resulting chain does not affect initial chain. + * Create a copy of current chain state. Consuming resulting chain does not affect initial chain */ public suspend fun fork(): Chain @@ -40,8 +39,8 @@ public fun Sequence.asChain(): Chain = iterator().asChain() * A simple chain of independent tokens. [fork] returns the same chain. */ public class SimpleChain(private val gen: suspend () -> R) : Chain { - override suspend fun next(): R = gen() - override suspend fun fork(): Chain = this + public override suspend fun next(): R = gen() + public override suspend fun fork(): Chain = this } /** @@ -53,21 +52,19 @@ public class MarkovChain(private val seed: suspend () -> R, private public fun value(): R? = value - override suspend fun next(): R = mutex.withLock { + public override suspend fun next(): R = mutex.withLock { val newValue = gen(value ?: seed()) value = newValue newValue } - override suspend fun fork(): Chain = MarkovChain(seed = { value ?: seed() }, gen = gen) + public override suspend fun fork(): Chain = MarkovChain(seed = { value ?: seed() }, gen = gen) } /** - * A chain with possibly mutable state. The state must not be changed outside the chain. Two chins should never share - * the state. - * - * @param S the state of the chain. - * @param forkState the function to copy current state without modifying it. + * A chain with possibly mutable state. The state must not be changed outside the chain. Two chins should never share the state + * @param S - the state of the chain + * @param forkState - the function to copy current state without modifying it */ public class StatefulChain( private val state: S, @@ -80,26 +77,26 @@ public class StatefulChain( public fun value(): R? = value - override suspend fun next(): R = mutex.withLock { + public override suspend fun next(): R = mutex.withLock { val newValue = state.gen(value ?: state.seed()) value = newValue newValue } - override suspend fun fork(): Chain = StatefulChain(forkState(state), seed, forkState, gen) + public override suspend fun fork(): Chain = StatefulChain(forkState(state), seed, forkState, gen) } /** * A chain that repeats the same value */ public class ConstantChain(public val value: T) : Chain { - override suspend fun next(): T = value - override suspend fun fork(): Chain = this + public override suspend fun next(): T = value + public override suspend fun fork(): Chain = this } /** * Map the chain result using suspended transformation. Initial chain result can no longer be safely consumed - * since mapped chain consumes tokens. Accepts regular transformation function. + * since mapped chain consumes tokens. Accepts regular transformation function */ public fun Chain.map(func: suspend (T) -> R): Chain = object : Chain { override suspend fun next(): R = func(this@map.next()) @@ -125,22 +122,20 @@ public fun Chain.filter(block: (T) -> Boolean): Chain = object : Chain /** * Map the whole chain */ -@UnstableKMathAPI -public fun Chain.combine(mapper: suspend (Chain) -> R): Chain = object : Chain { - override suspend fun next(): R = mapper(this@combine) - override suspend fun fork(): Chain = this@combine.fork().combine(mapper) +public fun Chain.collect(mapper: suspend (Chain) -> R): Chain = object : Chain { + override suspend fun next(): R = mapper(this@collect) + override suspend fun fork(): Chain = this@collect.fork().collect(mapper) } -@UnstableKMathAPI -public fun Chain.combineWithState( +public fun Chain.collectWithState( state: S, stateFork: (S) -> S, mapper: suspend S.(Chain) -> R, ): Chain = object : Chain { - override suspend fun next(): R = state.mapper(this@combineWithState) + override suspend fun next(): R = state.mapper(this@collectWithState) override suspend fun fork(): Chain = - this@combineWithState.fork().combineWithState(stateFork(state), stateFork, mapper) + this@collectWithState.fork().collectWithState(stateFork(state), stateFork, mapper) } /** diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt index 77d4203c5..ec1203740 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -10,12 +10,12 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.runningReduce import kotlinx.coroutines.flow.scan -import space.kscience.kmath.operations.GroupOps +import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -public fun Flow.cumulativeSum(group: GroupOps): Flow = +public fun Flow.cumulativeSum(group: GroupOperations): Flow = group { runningReduce { sum, element -> sum + element } } @ExperimentalCoroutinesApi diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt index 48be93b87..49f32f82f 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt @@ -1,14 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class) - package space.kscience.kmath.coroutines import kotlinx.coroutines.* -import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.produce import kotlinx.coroutines.flow.* @@ -18,33 +15,30 @@ public val Dispatchers.Math: CoroutineDispatcher /** * An imitator of [Deferred] which holds a suspended function block and dispatcher */ -@PublishedApi -internal class LazyDeferred(val dispatcher: CoroutineDispatcher, val block: suspend CoroutineScope.() -> T) { +internal class LazyDeferred(val dispatcher: CoroutineDispatcher, val block: suspend CoroutineScope.() -> T) { private var deferred: Deferred? = null - fun start(scope: CoroutineScope) { + internal fun start(scope: CoroutineScope) { if (deferred == null) deferred = scope.async(dispatcher, block = block) } suspend fun await(): T = deferred?.await() ?: error("Coroutine not started") } -public class AsyncFlow @PublishedApi internal constructor( - @PublishedApi internal val deferredFlow: Flow>, -) : Flow { +public class AsyncFlow internal constructor(internal val deferredFlow: Flow>) : Flow { override suspend fun collect(collector: FlowCollector): Unit = deferredFlow.collect { collector.emit((it.await())) } } -public inline fun Flow.async( +public fun Flow.async( dispatcher: CoroutineDispatcher = Dispatchers.Default, - crossinline block: suspend CoroutineScope.(T) -> R, + block: suspend CoroutineScope.(T) -> R, ): AsyncFlow { val flow = map { LazyDeferred(dispatcher) { block(it) } } return AsyncFlow(flow) } -public inline fun AsyncFlow.map(crossinline action: (T) -> R): AsyncFlow = +public fun AsyncFlow.map(action: (T) -> R): AsyncFlow = AsyncFlow(deferredFlow.map { input -> //TODO add function composition LazyDeferred(input.dispatcher) { @@ -58,7 +52,7 @@ public suspend fun AsyncFlow.collect(concurrency: Int, collector: FlowCol coroutineScope { //Starting up to N deferred coroutines ahead of time - val channel: ReceiveChannel> = produce(capacity = concurrency - 1) { + val channel = produce(capacity = concurrency - 1) { deferredFlow.collect { value -> value.start(this@coroutineScope) send(value) @@ -84,7 +78,9 @@ public suspend fun AsyncFlow.collect(concurrency: Int, collector: FlowCol public suspend inline fun AsyncFlow.collect( concurrency: Int, crossinline action: suspend (value: T) -> Unit, -): Unit = collect(concurrency, FlowCollector { value -> action(value) }) +): Unit = collect(concurrency, object : FlowCollector { + override suspend fun emit(value: T): Unit = action(value) +}) public inline fun Flow.mapParallel( dispatcher: CoroutineDispatcher = Dispatchers.Default, diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt index ccd329064..0d6a1178a 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt @@ -1,17 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:OptIn(FlowPreview::class) - package space.kscience.kmath.streaming import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.asFlow -import kotlinx.coroutines.flow.flatMapConcat -import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.* import space.kscience.kmath.chains.BlockingDoubleChain import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory @@ -25,6 +20,7 @@ public fun Buffer.asFlow(): Flow = iterator().asFlow() /** * Flat map a [Flow] of [Buffer] into continuous [Flow] of elements */ +@FlowPreview public fun Flow>.spread(): Flow = flatMapConcat { it.asFlow() } /** @@ -80,7 +76,7 @@ public fun Flow.chunked(bufferSize: Int): Flow = flow { /** * Map a flow to a moving window buffer. The window step is one. - * To get different steps, one could use skip operation. + * In order to get different steps, one could use skip operation. */ public fun Flow.windowed(window: Int): Flow> = flow { require(window > 1) { "Window size must be more than one" } diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt index 2ac8c1eb4..05f2876e3 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -22,10 +22,10 @@ public class RingBuffer( ) : Buffer { private val mutex: Mutex = Mutex() - override var size: Int = size + public override var size: Int = size private set - override operator fun get(index: Int): T { + public override operator fun get(index: Int): T { require(index >= 0) { "Index must be positive" } require(index < size) { "Index $index is out of circular buffer size $size" } return buffer[startIndex.forward(index)] as T @@ -36,7 +36,7 @@ public class RingBuffer( /** * Iterator could provide wrong results if buffer is changed in initialization (iteration is safe) */ - override operator fun iterator(): Iterator = object : AbstractIterator() { + public override operator fun iterator(): Iterator = object : AbstractIterator() { private var count = size private var index = startIndex val copy = buffer.copy() @@ -69,8 +69,6 @@ public class RingBuffer( @Suppress("NOTHING_TO_INLINE") private inline fun Int.forward(n: Int): Int = (this + n) % (buffer.size) - override fun toString(): String = Buffer.toString(this) - public companion object { public inline fun build(size: Int, empty: T): RingBuffer { val buffer = MutableBuffer.auto(size) { empty } as MutableBuffer diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt index a62bcc6b8..dd6e39071 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt index 22c2ac3ff..e2ecb4b2f 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt @@ -1,58 +1,50 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.structures import kotlinx.coroutines.* -import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.coroutines.Math -import space.kscience.kmath.nd.ColumnStrides -import space.kscience.kmath.nd.ShapeND +import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.StructureND -public class LazyStructureND( +public class LazyStructureND( public val scope: CoroutineScope, - override val shape: ShapeND, + public override val shape: IntArray, public val function: suspend (IntArray) -> T, ) : StructureND { private val cache: MutableMap> = HashMap() - public fun async(index: IntArray): Deferred = cache.getOrPut(index) { + public fun deferred(index: IntArray): Deferred = cache.getOrPut(index) { scope.async(context = Dispatchers.Math) { function(index) } } - public suspend fun await(index: IntArray): T = async(index).await() - @PerformancePitfall - override operator fun get(index: IntArray): T = runBlocking { async(index).await() } + public suspend fun await(index: IntArray): T = deferred(index).await() + public override operator fun get(index: IntArray): T = runBlocking { deferred(index).await() } - @OptIn(PerformancePitfall::class) - override fun elements(): Sequence> { - val strides = ColumnStrides(shape) - val res = runBlocking { strides.asSequence().toList().map { index -> index to await(index) } } + public override fun elements(): Sequence> { + val strides = DefaultStrides(shape) + val res = runBlocking { strides.indices().toList().map { index -> index to await(index) } } return res.asSequence() } } -@OptIn(PerformancePitfall::class) -public fun StructureND.async(index: IntArray): Deferred = - if (this is LazyStructureND) this@async.async(index) else CompletableDeferred(get(index)) +public fun StructureND.deferred(index: IntArray): Deferred = + if (this is LazyStructureND) deferred(index) else CompletableDeferred(get(index)) -@OptIn(PerformancePitfall::class) public suspend fun StructureND.await(index: IntArray): T = if (this is LazyStructureND) await(index) else get(index) /** * PENDING would benefit from KEEP-176 */ -@OptIn(PerformancePitfall::class) public inline fun StructureND.mapAsyncIndexed( scope: CoroutineScope, crossinline function: suspend (T, index: IntArray) -> R, ): LazyStructureND = LazyStructureND(scope, shape) { index -> function(get(index), index) } -@OptIn(PerformancePitfall::class) public inline fun StructureND.mapAsync( scope: CoroutineScope, crossinline function: suspend (T) -> R, diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt index c448168e3..9b67f7253 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt index a6d7f006c..32e3b2c74 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,7 +7,7 @@ package space.kscience.kmath.streaming import kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking -import space.kscience.kmath.operations.asSequence +import space.kscience.kmath.structures.asSequence import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-dimensions/README.md b/kmath-dimensions/README.md deleted file mode 100644 index 2e7250b51..000000000 --- a/kmath-dimensions/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-dimensions - -A proof of concept module for adding type-safe dimensions to structures - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-dimensions:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-dimensions:0.4.0-dev-1") -} -``` diff --git a/kmath-dimensions/build.gradle.kts b/kmath-dimensions/build.gradle.kts index be1fc65a0..a9a9177c0 100644 --- a/kmath-dimensions/build.gradle.kts +++ b/kmath-dimensions/build.gradle.kts @@ -1,23 +1,30 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + plugins { - id("space.kscience.gradle.mpp") -} - -kscience{ - jvm() - js() - native() - - dependencies{ - api(projects.kmathCore) - } - - dependencies(jvmMain) { - api(kotlin("reflect")) - } + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } description = "A proof of concept module for adding type-safe dimensions to structures" -readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE +kotlin.sourceSets { + commonMain { + dependencies { + api(project(":kmath-core")) + } + } + + jvmMain { + dependencies { + api(kotlin("reflect")) + } + } +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE } diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimensions.kt similarity index 64% rename from kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt rename to kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimensions.kt index 14677319c..8b17d252f 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -8,47 +8,47 @@ package space.kscience.kmath.dimensions import kotlin.reflect.KClass /** - * Represents a quantity of dimensions in certain structure. **This interface must be implemented only by objects.** + * Represents a quantity of dimensions in certain structure. * * @property dim The number of dimensions. */ public interface Dimension { - public val dim: Int + public val dim: UInt public companion object } -public fun KClass.dim(): Int = Dimension.resolve(this).dim +public fun KClass.dim(): UInt = Dimension.resolve(this).dim public expect fun Dimension.Companion.resolve(type: KClass): D /** * Finds or creates [Dimension] with [Dimension.dim] equal to [dim]. */ -public expect fun Dimension.Companion.of(dim: Int): Dimension +public expect fun Dimension.Companion.of(dim: UInt): Dimension /** * Finds [Dimension.dim] of given type [D]. */ -public inline fun Dimension.Companion.dim(): Int = D::class.dim() +public inline fun Dimension.Companion.dim(): UInt = D::class.dim() /** * Type representing 1 dimension. */ public object D1 : Dimension { - override val dim: Int get() = 1 + override val dim: UInt get() = 1U } /** * Type representing 2 dimensions. */ public object D2 : Dimension { - override val dim: Int get() = 2 + override val dim: UInt get() = 2U } /** * Type representing 3 dimensions. */ public object D3 : Dimension { - override val dim: Int get() = 3 + override val dim: UInt get() = 3U } diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt index dde2d4fcf..2ebcc454d 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt @@ -1,32 +1,33 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.dimensions -import space.kscience.kmath.linear.* -import space.kscience.kmath.nd.ShapeND +import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.linear.Point +import space.kscience.kmath.linear.transpose import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.algebra import kotlin.jvm.JvmInline /** * A matrix with compile-time controlled dimension */ -public interface DMatrix : Structure2D { +public interface DMatrix : Structure2D { public companion object { /** - * Coerces a regular matrix to a matrix with type-safe dimensions and throws an error if coercion failed + * Coerces a regular matrix to a matrix with type-safe dimensions and throws a error if coercion failed */ public inline fun coerce(structure: Structure2D): DMatrix { - require(structure.rowNum == Dimension.dim()) { + require(structure.rowNum == Dimension.dim().toInt()) { "Row number mismatch: expected ${Dimension.dim()} but found ${structure.rowNum}" } - require(structure.colNum == Dimension.dim()) { + require(structure.colNum == Dimension.dim().toInt()) { "Column number mismatch: expected ${Dimension.dim()} but found ${structure.colNum}" } @@ -34,7 +35,7 @@ public interface DMatrix : Structure2D { } /** - * The same as [DMatrix.coerce] but without dimension checks. Use with caution. + * The same as [DMatrix.coerce] but without dimension checks. Use with caution */ public fun coerceUnsafe(structure: Structure2D): DMatrix = DMatrixWrapper(structure) @@ -45,10 +46,10 @@ public interface DMatrix : Structure2D { * An inline wrapper for a Matrix */ @JvmInline -public value class DMatrixWrapper( +public value class DMatrixWrapper( private val structure: Structure2D, ) : DMatrix { - override val shape: ShapeND get() = structure.shape + override val shape: IntArray get() = structure.shape override val rowNum: Int get() = shape[0] override val colNum: Int get() = shape[1] override operator fun get(i: Int, j: Int): T = structure[i, j] @@ -57,10 +58,10 @@ public value class DMatrixWrapper( /** * Dimension-safe point */ -public interface DPoint : Point { +public interface DPoint : Point { public companion object { public inline fun coerce(point: Point): DPoint { - require(point.size == Dimension.dim()) { + require(point.size == Dimension.dim().toInt()) { "Vector dimension mismatch: expected ${Dimension.dim()}, but found ${point.size}" } @@ -75,7 +76,7 @@ public interface DPoint : Point { * Dimension-safe point wrapper */ @JvmInline -public value class DPointWrapper(public val point: Point) : +public value class DPointWrapper(public val point: Point) : DPoint { override val size: Int get() = point.size @@ -91,11 +92,11 @@ public value class DPointWrapper(public val point: Point>(public val context: LinearSpace) { public inline fun Matrix.coerce(): DMatrix { - require(rowNum == Dimension.dim()) { + require(rowNum == Dimension.dim().toInt()) { "Row number mismatch: expected ${Dimension.dim()} but found $rowNum" } - require(colNum == Dimension.dim()) { + require(colNum == Dimension.dim().toInt()) { "Column number mismatch: expected ${Dimension.dim()} but found $colNum" } @@ -110,7 +111,7 @@ public value class DMatrixContext>(public val context: ): DMatrix { val rows = Dimension.dim() val cols = Dimension.dim() - return context.buildMatrix(rows, cols, initializer).coerce() + return context.buildMatrix(rows.toInt(), cols.toInt(), initializer).coerce() } public inline fun point(noinline initializer: A.(Int) -> T): DPoint { @@ -118,7 +119,7 @@ public value class DMatrixContext>(public val context: return DPoint.coerceUnsafe( context.buildVector( - size, + size.toInt(), initializer ) ) @@ -150,7 +151,7 @@ public value class DMatrixContext>(public val context: context.run { (this@transpose as Matrix).transpose() }.coerce() public companion object { - public val real: DMatrixContext = DMatrixContext(Double.algebra.linearSpace) + public val real: DMatrixContext = DMatrixContext(LinearSpace.real) } } @@ -166,4 +167,4 @@ public inline fun DMatrixContext.on public inline fun DMatrixContext.zero(): DMatrix = produce { _, _ -> 0.0 - } + } \ No newline at end of file diff --git a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt similarity index 95% rename from kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt rename to kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt index e2793855b..59260fe73 100644 --- a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt +++ b/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/dimJs.kt similarity index 57% rename from kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt rename to kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/dimJs.kt index 1ae484228..27912f5bc 100644 --- a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/dimJs.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,17 +7,17 @@ package space.kscience.kmath.dimensions import kotlin.reflect.KClass -private val dimensionMap: MutableMap = hashMapOf(1 to D1, 2 to D2, 3 to D3) +private val dimensionMap: MutableMap = hashMapOf(1u to D1, 2u to D2, 3u to D3) @Suppress("UNCHECKED_CAST") public actual fun Dimension.Companion.resolve(type: KClass): D = dimensionMap .entries - .map(MutableMap.MutableEntry::value) + .map(MutableMap.MutableEntry::value) .find { it::class == type } as? D ?: error("Can't resolve dimension $type") -public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) { +public actual fun Dimension.Companion.of(dim: UInt): Dimension = dimensionMap.getOrPut(dim) { object : Dimension { - override val dim: Int get() = dim + override val dim: UInt get() = dim } } diff --git a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/dimJvm.kt similarity index 63% rename from kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt rename to kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/dimJvm.kt index 24cfb14e8..f21a3e18f 100644 --- a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/dimJvm.kt @@ -1,10 +1,8 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:JvmName("DimensionJVM") - package space.kscience.kmath.dimensions import kotlin.reflect.KClass @@ -12,12 +10,12 @@ import kotlin.reflect.KClass public actual fun Dimension.Companion.resolve(type: KClass): D = type.objectInstance ?: error("No object instance for dimension class") -public actual fun Dimension.Companion.of(dim: Int): Dimension = when (dim) { - 1 -> D1 - 2 -> D2 - 3 -> D3 +public actual fun Dimension.Companion.of(dim: UInt): Dimension = when (dim) { + 1u -> D1 + 2u -> D2 + 3u -> D3 else -> object : Dimension { - override val dim: Int get() = dim + override val dim: UInt get() = dim } -} +} \ No newline at end of file diff --git a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/dimNative.kt similarity index 60% rename from kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt rename to kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/dimNative.kt index f5f749c8a..9aa58e64a 100644 --- a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/dimNative.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -9,17 +9,17 @@ import kotlin.native.concurrent.ThreadLocal import kotlin.reflect.KClass @ThreadLocal -private val dimensionMap: MutableMap = hashMapOf(1 to D1, 2 to D2, 3 to D3) +private val dimensionMap: MutableMap = hashMapOf(1u to D1, 2u to D2, 3u to D3) @Suppress("UNCHECKED_CAST") public actual fun Dimension.Companion.resolve(type: KClass): D = dimensionMap .entries - .map(MutableMap.MutableEntry::value) + .map(MutableMap.MutableEntry::value) .find { it::class == type } as? D ?: error("Can't resolve dimension $type") -public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) { +public actual fun Dimension.Companion.of(dim: UInt): Dimension = dimensionMap.getOrPut(dim) { object : Dimension { - override val dim: Int get() = dim + override val dim: UInt get() = dim } } diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index ad80ba183..cae11724d 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -2,34 +2,36 @@ EJML based linear algebra implementation. - - [ejml-vector](src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : Point implementations. - - [ejml-matrix](src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : Matrix implementation. - - [ejml-linear-space](src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : LinearSpace implementations. + - [ejml-vector](src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : The Point implementation using SimpleMatrix. + - [ejml-matrix](src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : The Matrix implementation using SimpleMatrix. + - [ejml-linear-space](src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : The LinearSpace implementation using SimpleMatrix. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.4.0-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-6`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } - mavenCentral() + maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap } dependencies { - implementation 'space.kscience:kmath-ejml:0.4.0-dev-1' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-6' } ``` **Gradle Kotlin DSL:** ```kotlin repositories { maven("https://repo.kotlin.link") - mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap + maven("https://dl.bintray.com/hotkeytlt/maven") // required for a } dependencies { - implementation("space.kscience:kmath-ejml:0.4.0-dev-1") + implementation("space.kscience:kmath-ejml:0.3.0-dev-6") } ``` diff --git a/kmath-ejml/build.gradle.kts b/kmath-ejml/build.gradle.kts index d7f780d79..6ae0dcec6 100644 --- a/kmath-ejml/build.gradle.kts +++ b/kmath-ejml/build.gradle.kts @@ -1,41 +1,39 @@ -import space.kscience.kmath.ejml.codegen.ejmlCodegen +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity plugins { - id("space.kscience.gradle.jvm") + kotlin("jvm") + id("ru.mipt.npm.gradle.common") } dependencies { - api("org.ejml:ejml-ddense:0.41") - api("org.ejml:ejml-fdense:0.41") - api("org.ejml:ejml-dsparse:0.41") - api("org.ejml:ejml-fsparse:0.41") + api("org.ejml:ejml-simple:0.40") api(project(":kmath-core")) } readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE + maturity = Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( id = "ejml-vector", + description = "The Point implementation using SimpleMatrix.", ref = "src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt" - ) { "Point implementations." } + ) feature( id = "ejml-matrix", + description = "The Matrix implementation using SimpleMatrix.", ref = "src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt" - ) { "Matrix implementation." } + ) feature( id = "ejml-linear-space", + description = "The LinearSpace implementation using SimpleMatrix.", ref = "src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt" - ) { "LinearSpace implementations." } -} - -kotlin.sourceSets.main { - val codegen by tasks.creating { - ejmlCodegen(kotlin.srcDirs.first().absolutePath + "/space/kscience/kmath/ejml/_generated.kt") - } - - kotlin.srcDirs(files().builtBy(codegen)) + ) } diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt index 8925fb045..4b6421c9b 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt @@ -1,47 +1,209 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ejml -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.linear.InverseMatrixFeature -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.linear.Point -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.operations.Ring +import org.ejml.dense.row.factory.DecompositionFactory_DDRM +import org.ejml.simple.SimpleMatrix +import space.kscience.kmath.linear.* +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.StructureFeature +import space.kscience.kmath.nd.getFeature +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.structures.DoubleBuffer +import kotlin.reflect.KClass +import kotlin.reflect.cast /** - * [LinearSpace] implementation specialized for a certain EJML type. + * Represents context of basic operations operating with [EjmlMatrix]. * - * @param T the type of items in the matrices. - * @param A the element context type. - * @param M the EJML matrix type. * @author Iaroslav Postovalov + * @author Alexander Nozik */ -public abstract class EjmlLinearSpace, out M : org.ejml.data.Matrix> : LinearSpace { +public object EjmlLinearSpace : LinearSpace { + /** + * The [DoubleField] reference. + */ + public override val elementAlgebra: DoubleField get() = DoubleField + /** * Converts this matrix to EJML one. */ - public abstract fun Matrix.toEjml(): EjmlMatrix + @OptIn(UnstableKMathAPI::class) + public fun Matrix.toEjml(): EjmlMatrix = when (val matrix = origin) { + is EjmlMatrix -> matrix + else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } + } /** * Converts this vector to EJML one. */ - public abstract fun Point.toEjml(): EjmlVector + public fun Point.toEjml(): EjmlVector = when (this) { + is EjmlVector -> this + else -> EjmlVector(SimpleMatrix(size, 1).also { + (0 until it.numRows()).forEach { row -> it[row, 0] = get(row) } + }) + } - public abstract override fun buildMatrix( + public override fun buildMatrix( rows: Int, columns: Int, - initializer: A.(i: Int, j: Int) -> T, - ): EjmlMatrix + initializer: DoubleField.(i: Int, j: Int) -> Double, + ): EjmlMatrix = EjmlMatrix(SimpleMatrix(rows, columns).also { + (0 until rows).forEach { row -> + (0 until columns).forEach { col -> it[row, col] = DoubleField.initializer(row, col) } + } + }) - public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector + public override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): Point = + EjmlVector(SimpleMatrix(size, 1).also { + (0 until it.numRows()).forEach { row -> it[row, 0] = DoubleField.initializer(row) } + }) + + private fun SimpleMatrix.wrapMatrix() = EjmlMatrix(this) + private fun SimpleMatrix.wrapVector() = EjmlVector(this) + + public override fun Matrix.unaryMinus(): Matrix = this * (-1.0) + + public override fun Matrix.dot(other: Matrix): EjmlMatrix = + EjmlMatrix(toEjml().origin.mult(other.toEjml().origin)) + + public override fun Matrix.dot(vector: Point): EjmlVector = + EjmlVector(toEjml().origin.mult(vector.toEjml().origin)) + + public override operator fun Matrix.minus(other: Matrix): EjmlMatrix = + (toEjml().origin - other.toEjml().origin).wrapMatrix() + + public override operator fun Matrix.times(value: Double): EjmlMatrix = + toEjml().origin.scale(value).wrapMatrix() + + public override fun Point.unaryMinus(): EjmlVector = + toEjml().origin.negative().wrapVector() + + public override fun Matrix.plus(other: Matrix): EjmlMatrix = + (toEjml().origin + other.toEjml().origin).wrapMatrix() + + public override fun Point.plus(other: Point): EjmlVector = + (toEjml().origin + other.toEjml().origin).wrapVector() + + public override fun Point.minus(other: Point): EjmlVector = + (toEjml().origin - other.toEjml().origin).wrapVector() + + public override fun Double.times(m: Matrix): EjmlMatrix = + m.toEjml().origin.scale(this).wrapMatrix() + + public override fun Point.times(value: Double): EjmlVector = + toEjml().origin.scale(value).wrapVector() + + public override fun Double.times(v: Point): EjmlVector = + v.toEjml().origin.scale(this).wrapVector() - @Suppress("UNCHECKED_CAST") @UnstableKMathAPI - public fun EjmlMatrix.inverse(): Structure2D = - computeFeature(this, InverseMatrixFeature::class)?.inverse as Structure2D + public override fun getFeature(structure: Matrix, type: KClass): F? { + //Return the feature if it is intrinsic to the structure + structure.getFeature(type)?.let { return it } + + val origin = structure.toEjml().origin + + return when (type) { + InverseMatrixFeature::class -> object : InverseMatrixFeature { + override val inverse: Matrix by lazy { EjmlMatrix(origin.invert()) } + } + + DeterminantFeature::class -> object : DeterminantFeature { + override val determinant: Double by lazy(origin::determinant) + } + + SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { + private val svd by lazy { + DecompositionFactory_DDRM.svd(origin.numRows(), origin.numCols(), true, true, false) + .apply { decompose(origin.ddrm.copy()) } + } + + override val u: Matrix by lazy { EjmlMatrix(SimpleMatrix(svd.getU(null, false))) } + override val s: Matrix by lazy { EjmlMatrix(SimpleMatrix(svd.getW(null))) } + override val v: Matrix by lazy { EjmlMatrix(SimpleMatrix(svd.getV(null, false))) } + override val singularValues: Point by lazy { DoubleBuffer(svd.singularValues) } + } + + QRDecompositionFeature::class -> object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_DDRM.qr().apply { decompose(origin.ddrm.copy()) } + } + + override val q: Matrix by lazy { + EjmlMatrix(SimpleMatrix(qr.getQ(null, false))) + OrthogonalFeature + } + + override val r: Matrix by lazy { EjmlMatrix(SimpleMatrix(qr.getR(null, false))) + UFeature } + } + + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { + val cholesky = + DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.ddrm.copy()) } + + EjmlMatrix(SimpleMatrix(cholesky.getT(null))) + LFeature + } + } + + LupDecompositionFeature::class -> object : LupDecompositionFeature { + private val lup by lazy { + DecompositionFactory_DDRM.lu(origin.numRows(), origin.numCols()) + .apply { decompose(origin.ddrm.copy()) } + } + + override val l: Matrix by lazy { + EjmlMatrix(SimpleMatrix(lup.getLower(null))) + LFeature + } + + override val u: Matrix by lazy { + EjmlMatrix(SimpleMatrix(lup.getUpper(null))) + UFeature + } + + override val p: Matrix by lazy { EjmlMatrix(SimpleMatrix(lup.getRowPivot(null))) } + } + + else -> null + }?.let(type::cast) + } } + +/** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p matrix. + * @return the solution for 'x' that is n by p. + * @author Iaroslav Postovalov + */ +public fun EjmlLinearSpace.solve(a: Matrix, b: Matrix): EjmlMatrix = + EjmlMatrix(a.toEjml().origin.solve(b.toEjml().origin)) + +/** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p vector. + * @return the solution for 'x' that is n by p. + * @author Iaroslav Postovalov + */ +public fun EjmlLinearSpace.solve(a: Matrix, b: Point): EjmlVector = + EjmlVector(a.toEjml().origin.solve(b.toEjml().origin)) + +/** + * Inverts this matrix. + * + * @author Alexander Nozik + */ +@OptIn(UnstableKMathAPI::class) +public fun EjmlMatrix.inverted(): EjmlMatrix = getFeature>()!!.inverse as EjmlMatrix + +/** + * Inverts the given matrix. + * + * @author Alexander Nozik + */ +public fun EjmlLinearSpace.inverse(matrix: Matrix): Matrix = matrix.toEjml().inverted() \ No newline at end of file diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt index 1d70c0e7d..32907d199 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt @@ -1,22 +1,22 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ejml -import org.ejml.data.Matrix -import space.kscience.kmath.nd.Structure2D +import org.ejml.simple.SimpleMatrix +import space.kscience.kmath.linear.Matrix /** - * [space.kscience.kmath.linear.Matrix] implementation based on EJML [Matrix]. + * The matrix implementation over EJML [SimpleMatrix]. * - * @param T the type of elements contained in the buffer. - * @param M the type of EJML matrix. - * @property origin The underlying EJML matrix. + * @property origin the underlying [SimpleMatrix]. * @author Iaroslav Postovalov */ -public abstract class EjmlMatrix(public open val origin: M) : Structure2D { - override val rowNum: Int get() = origin.numRows - override val colNum: Int get() = origin.numCols +public class EjmlMatrix(public val origin: SimpleMatrix) : Matrix { + public override val rowNum: Int get() = origin.numRows() + public override val colNum: Int get() = origin.numCols() + + public override operator fun get(i: Int, j: Int): Double = origin[i, j] } diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt index c4fae9951..2f4b4a8e2 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt @@ -1,35 +1,39 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ejml -import org.ejml.data.Matrix +import org.ejml.simple.SimpleMatrix import space.kscience.kmath.linear.Point /** - * [Point] implementation based on EJML [Matrix]. + * Represents point over EJML [SimpleMatrix]. * - * @param T the type of elements contained in the buffer. - * @param M the type of EJML matrix. - * @property origin The underlying matrix, must have only one row. + * @property origin the underlying [SimpleMatrix]. * @author Iaroslav Postovalov */ -public abstract class EjmlVector(public open val origin: M) : Point { - override val size: Int - get() = origin.numCols +public class EjmlVector internal constructor(public val origin: SimpleMatrix) : Point { + public override val size: Int + get() = origin.numRows() - override operator fun iterator(): Iterator = object : Iterator { - private var cursor: Int = 0 - - override fun next(): T { - cursor += 1 - return this@EjmlVector[cursor - 1] - } - - override fun hasNext(): Boolean = cursor < origin.numCols * origin.numRows + init { + require(origin.numCols() == 1) { "Only single column matrices are allowed" } } - override fun toString(): String = "EjmlVector(origin=$origin)" + public override operator fun get(index: Int): Double = origin[index] + + public override operator fun iterator(): Iterator = object : Iterator { + private var cursor: Int = 0 + + override fun next(): Double { + cursor += 1 + return origin[cursor - 1] + } + + override fun hasNext(): Boolean = cursor < origin.numCols() * origin.numRows() + } + + public override fun toString(): String = "EjmlVector(origin=$origin)" } diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt deleted file mode 100644 index c56583fa8..000000000 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt +++ /dev/null @@ -1,1003 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */ - -package space.kscience.kmath.ejml - -import org.ejml.data.* -import org.ejml.dense.row.CommonOps_DDRM -import org.ejml.dense.row.CommonOps_FDRM -import org.ejml.dense.row.factory.DecompositionFactory_DDRM -import org.ejml.dense.row.factory.DecompositionFactory_FDRM -import org.ejml.sparse.FillReducing -import org.ejml.sparse.csc.CommonOps_DSCC -import org.ejml.sparse.csc.CommonOps_FSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.linear.* -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.FloatField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.FloatBuffer -import kotlin.reflect.KClass -import kotlin.reflect.cast - -/** - * [EjmlVector] specialization for [Double]. - */ -public class EjmlDoubleVector(override val origin: M) : EjmlVector(origin) { - init { - require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } - } - - override operator fun get(index: Int): Double = origin[0, index] -} - -/** - * [EjmlVector] specialization for [Float]. - */ -public class EjmlFloatVector(override val origin: M) : EjmlVector(origin) { - init { - require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } - } - - override operator fun get(index: Int): Float = origin[0, index] -} - -/** - * [EjmlMatrix] specialization for [Double]. - */ -public class EjmlDoubleMatrix(override val origin: M) : EjmlMatrix(origin) { - override operator fun get(i: Int, j: Int): Double = origin[i, j] -} - -/** - * [EjmlMatrix] specialization for [Float]. - */ -public class EjmlFloatMatrix(override val origin: M) : EjmlMatrix(origin) { - override operator fun get(i: Int, j: Int): Float = origin[i, j] -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_DDRM], [DecompositionFactory_DDRM] operations and - * [DMatrixRMaj] matrices. - */ -public object EjmlLinearSpaceDDRM : EjmlLinearSpace() { - /** - * The [DoubleField] reference. - */ - override val elementAlgebra: DoubleField get() = DoubleField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlDoubleMatrix = when { - this is EjmlDoubleMatrix<*> && origin is DMatrixRMaj -> this as EjmlDoubleMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlDoubleVector = when { - this is EjmlDoubleVector<*> && origin is DMatrixRMaj -> this as EjmlDoubleVector - else -> EjmlDoubleVector(DMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double, - ): EjmlDoubleMatrix = DMatrixRMaj(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: DoubleField.(Int) -> Double, - ): EjmlDoubleVector = EjmlDoubleVector(DMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlDoubleMatrix(this) - private fun T.wrapVector() = EjmlDoubleVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - CommonOps_DDRM.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - CommonOps_DDRM.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - - override fun Point.times(value: Double): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Double.times(v: Point): EjmlDoubleVector = v * this - - @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - InverseMatrixFeature::class -> object : InverseMatrixFeature { - override val inverse: Matrix by lazy { - val res = origin.copy() - CommonOps_DDRM.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature { - override val determinant: Double by lazy { CommonOps_DDRM.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { - private val svd by lazy { - DecompositionFactory_DDRM.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point by lazy { DoubleBuffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix().withFeature(LFeature) - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature { - private val lup by lazy { - DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lup.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } - } - - else -> null - }?.let{ - type.cast(it) - } - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) - return EjmlDoubleVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_FDRM], [DecompositionFactory_FDRM] operations and - * [FMatrixRMaj] matrices. - */ -public object EjmlLinearSpaceFDRM : EjmlLinearSpace() { - /** - * The [FloatField] reference. - */ - override val elementAlgebra: FloatField get() = FloatField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlFloatMatrix = when { - this is EjmlFloatMatrix<*> && origin is FMatrixRMaj -> this as EjmlFloatMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlFloatVector = when { - this is EjmlFloatVector<*> && origin is FMatrixRMaj -> this as EjmlFloatVector - else -> EjmlFloatVector(FMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: FloatField.(i: Int, j: Int) -> Float, - ): EjmlFloatMatrix = FMatrixRMaj(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: FloatField.(Int) -> Float, - ): EjmlFloatVector = EjmlFloatVector(FMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlFloatMatrix(this) - private fun T.wrapVector() = EjmlFloatVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - CommonOps_FDRM.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - CommonOps_FDRM.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Float): EjmlFloatMatrix { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - - override fun Point.times(value: Float): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Float.times(v: Point): EjmlFloatVector = v * this - - @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - InverseMatrixFeature::class -> object : InverseMatrixFeature { - override val inverse: Matrix by lazy { - val res = origin.copy() - CommonOps_FDRM.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature { - override val determinant: Float by lazy { CommonOps_FDRM.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { - private val svd by lazy { - DecompositionFactory_FDRM.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point by lazy { FloatBuffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_FDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix().withFeature(LFeature) - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature { - private val lup by lazy { - DecompositionFactory_FDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lup.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } - } - - else -> null - }?.let{ - type.cast(it) - } - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) - return EjmlFloatVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_DSCC], [DecompositionFactory_DSCC] operations and - * [DMatrixSparseCSC] matrices. - */ -public object EjmlLinearSpaceDSCC : EjmlLinearSpace() { - /** - * The [DoubleField] reference. - */ - override val elementAlgebra: DoubleField get() = DoubleField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlDoubleMatrix = when { - this is EjmlDoubleMatrix<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlDoubleVector = when { - this is EjmlDoubleVector<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleVector - else -> EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double, - ): EjmlDoubleMatrix = DMatrixSparseCSC(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: DoubleField.(Int) -> Double, - ): EjmlDoubleVector = EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlDoubleMatrix(this) - private fun T.wrapVector() = EjmlDoubleVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - - override fun Point.times(value: Double): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Double.times(v: Point): EjmlDoubleVector = v * this - - @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as DMatrix).wrapMatrix().withFeature(LFeature) - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { - private val lu by lazy { - DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lu.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val inverse: Matrix by lazy { - var a = origin - val inverse = DMatrixRMaj(1, 1) - val solver = LinearSolverFactory_DSCC.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_DDRM.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: Double by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - } - - else -> null - }?.let{ - type.cast(it) - } - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) - return EjmlDoubleVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_FSCC], [DecompositionFactory_FSCC] operations and - * [FMatrixSparseCSC] matrices. - */ -public object EjmlLinearSpaceFSCC : EjmlLinearSpace() { - /** - * The [FloatField] reference. - */ - override val elementAlgebra: FloatField get() = FloatField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlFloatMatrix = when { - this is EjmlFloatMatrix<*> && origin is FMatrixSparseCSC -> this as EjmlFloatMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlFloatVector = when { - this is EjmlFloatVector<*> && origin is FMatrixSparseCSC -> this as EjmlFloatVector - else -> EjmlFloatVector(FMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: FloatField.(i: Int, j: Int) -> Float, - ): EjmlFloatMatrix = FMatrixSparseCSC(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: FloatField.(Int) -> Float, - ): EjmlFloatVector = EjmlFloatVector(FMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlFloatMatrix(this) - private fun T.wrapVector() = EjmlFloatVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Float): EjmlFloatMatrix { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - - override fun Point.times(value: Float): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Float.times(v: Point): EjmlFloatVector = v * this - - @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_FSCC.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as FMatrix).wrapMatrix().withFeature(LFeature) - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { - private val lu by lazy { - DecompositionFactory_FSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lu.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val inverse: Matrix by lazy { - var a = origin - val inverse = FMatrixRMaj(1, 1) - val solver = LinearSolverFactory_FSCC.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_FDRM.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: Float by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - } - - else -> null - }?.let{ - type.cast(it) - } - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) - return EjmlFloatVector(res) - } -} - diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt index e89810e0d..59f9602d6 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt @@ -1,107 +1,86 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:OptIn(PerformancePitfall::class) - package space.kscience.kmath.ejml -import org.ejml.data.DMatrixRMaj -import org.ejml.dense.row.CommonOps_DDRM -import org.ejml.dense.row.RandomMatrices_DDRM import org.ejml.dense.row.factory.DecompositionFactory_DDRM -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI +import org.ejml.simple.SimpleMatrix import space.kscience.kmath.linear.* +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.toArray -import space.kscience.kmath.operations.algebra +import space.kscience.kmath.nd.getFeature import kotlin.random.Random import kotlin.random.asJavaRandom import kotlin.test.* -internal fun assertMatrixEquals(expected: StructureND, actual: StructureND) { +fun assertMatrixEquals(expected: StructureND, actual: StructureND) { assertTrue { StructureND.contentEquals(expected, actual) } } -@OptIn(UnstableKMathAPI::class) internal class EjmlMatrixTest { private val random = Random(0) - private val randomMatrix: DMatrixRMaj + private val randomMatrix: SimpleMatrix get() { val s = random.nextInt(2, 100) - val d = DMatrixRMaj(s, s) - RandomMatrices_DDRM.fillUniform(d, random.asJavaRandom()) - return d + return SimpleMatrix.random_DDRM(s, s, 0.0, 10.0, random.asJavaRandom()) } @Test fun rowNum() { val m = randomMatrix - assertEquals(m.numRows, EjmlDoubleMatrix(m).rowNum) + assertEquals(m.numRows(), EjmlMatrix(m).rowNum) } @Test fun colNum() { val m = randomMatrix - assertEquals(m.numCols, EjmlDoubleMatrix(m).rowNum) + assertEquals(m.numCols(), EjmlMatrix(m).rowNum) } @Test fun shape() { val m = randomMatrix - val w = EjmlDoubleMatrix(m) - assertContentEquals(intArrayOf(m.numRows, m.numCols), w.shape.toArray()) + val w = EjmlMatrix(m) + assertEquals(listOf(m.numRows(), m.numCols()), w.shape.toList()) } @OptIn(UnstableKMathAPI::class) @Test fun features() { val m = randomMatrix - val w = EjmlDoubleMatrix(m) - val det: DeterminantFeature = EjmlLinearSpaceDDRM.computeFeature(w) ?: fail() - assertEquals(CommonOps_DDRM.det(m), det.determinant) - val lup: LupDecompositionFeature = EjmlLinearSpaceDDRM.computeFeature(w) ?: fail() + val w = EjmlMatrix(m) + val det: DeterminantFeature = EjmlLinearSpace.getFeature(w) ?: fail() + assertEquals(m.determinant(), det.determinant) + val lup: LupDecompositionFeature = EjmlLinearSpace.getFeature(w) ?: fail() - val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols) - .also { it.decompose(m.copy()) } + val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows(), m.numCols()) + .also { it.decompose(m.ddrm.copy()) } - assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getLower(null)), lup.l) - assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getUpper(null)), lup.u) - assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getRowPivot(null)), lup.p) + assertMatrixEquals(EjmlMatrix(SimpleMatrix(ludecompositionF64.getLower(null))), lup.l) + assertMatrixEquals(EjmlMatrix(SimpleMatrix(ludecompositionF64.getUpper(null))), lup.u) + assertMatrixEquals(EjmlMatrix(SimpleMatrix(ludecompositionF64.getRowPivot(null))), lup.p) + } + + private object SomeFeature : MatrixFeature {} + + @OptIn(UnstableKMathAPI::class) + @Test + fun suggestFeature() { + assertNotNull((EjmlMatrix(randomMatrix) + SomeFeature).getFeature()) } @Test fun get() { val m = randomMatrix - assertEquals(m[0, 0], EjmlDoubleMatrix(m)[0, 0]) + assertEquals(m[0, 0], EjmlMatrix(m)[0, 0]) } @Test fun origin() { val m = randomMatrix - assertSame(m, EjmlDoubleMatrix(m).origin) - } - - @Test - fun inverse() = EjmlLinearSpaceDDRM { - val random = Random(1224) - val dim = 20 - - val space = Double.algebra.linearSpace - - //creating invertible matrix - val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 } - val matrix = space { l dot u } - val inverted = matrix.toEjml().inverse() - - val res = matrix dot inverted - - println(StructureND.toString(res)) - - assertTrue { StructureND.contentEquals(one(dim, dim), res, 1e-3) } + assertSame(m, EjmlMatrix(m).origin) } } diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt index 7d3ea314b..e1bcd269e 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt @@ -1,12 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.ejml -import org.ejml.data.DMatrixRMaj -import org.ejml.dense.row.RandomMatrices_DDRM +import org.ejml.simple.SimpleMatrix import kotlin.random.Random import kotlin.random.asJavaRandom import kotlin.test.Test @@ -16,34 +15,30 @@ import kotlin.test.assertSame internal class EjmlVectorTest { private val random = Random(0) - private val randomMatrix: DMatrixRMaj - get() { - val d = DMatrixRMaj(1, random.nextInt(2, 100)) - RandomMatrices_DDRM.fillUniform(d, random.asJavaRandom()) - return d - } + private val randomMatrix: SimpleMatrix + get() = SimpleMatrix.random_DDRM(random.nextInt(2, 100), 1, 0.0, 10.0, random.asJavaRandom()) @Test fun size() { val m = randomMatrix - val w = EjmlDoubleVector(m) - assertEquals(m.numCols, w.size) + val w = EjmlVector(m) + assertEquals(m.numRows(), w.size) } @Test fun get() { val m = randomMatrix - val w = EjmlDoubleVector(m) + val w = EjmlVector(m) assertEquals(m[0, 0], w[0]) } @Test fun iterator() { val m = randomMatrix - val w = EjmlDoubleVector(m) + val w = EjmlVector(m) assertEquals( - m.iterator(true, 0, 0, 0, m.numCols - 1).asSequence().toList(), + m.iterator(true, 0, 0, m.numRows() - 1, 0).asSequence().toList(), w.iterator().asSequence().toList() ) } @@ -51,7 +46,7 @@ internal class EjmlVectorTest { @Test fun origin() { val m = randomMatrix - val w = EjmlDoubleVector(m) + val w = EjmlVector(m) assertSame(m, w.origin) } } diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 638b15bfa..922e6572b 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,27 +9,29 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.4.0-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-6`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } - mavenCentral() + maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap } dependencies { - implementation 'space.kscience:kmath-for-real:0.4.0-dev-1' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-6' } ``` **Gradle Kotlin DSL:** ```kotlin repositories { maven("https://repo.kotlin.link") - mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap + maven("https://dl.bintray.com/hotkeytlt/maven") // required for a } dependencies { - implementation("space.kscience:kmath-for-real:0.4.0-dev-1") + implementation("space.kscience:kmath-for-real:0.3.0-dev-6") } ``` diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts index 99ce5903f..fc454205b 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -1,48 +1,45 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity + plugins { - id("space.kscience.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") } -kscience { - jvm() - js() - native() - +kotlin.sourceSets.commonMain { dependencies { - api(projects.kmathCore) - } - - testDependencies { - implementation(projects.testUtils) + api(project(":kmath-core")) } } readme { description = """ - Extension module that should be used to achieve numpy-like behavior. + Extension module that should be used to achieve numpy-like behavior. All operations are specialized to work with `Double` numbers without declaring algebraic contexts. One can still use generic algebras though. """.trimIndent() - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + maturity = Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( id = "DoubleVector", + description = "Numpy-like operations for Buffers/Points", ref = "src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt" - ) { - "Numpy-like operations for Buffers/Points" - } + ) feature( id = "DoubleMatrix", + description = "Numpy-like operations for 2d real structures", ref = "src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt" - ) { - "Numpy-like operations for 2d real structures" - } + ) feature( id = "grids", + description = "Uniform grid generators", ref = "src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt" - ) { - "Uniform grid generators" - } + ) } diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt index 40e4a91f1..c4656dd8a 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt @@ -1,21 +1,16 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:OptIn(PerformancePitfall::class) -@file:Suppress("unused") - package space.kscience.kmath.real -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.* +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.asIterable import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.asIterable import kotlin.math.pow /* @@ -33,18 +28,18 @@ import kotlin.math.pow public typealias RealMatrix = Matrix public fun realMatrix(rowNum: Int, colNum: Int, initializer: DoubleField.(i: Int, j: Int) -> Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum, initializer) + LinearSpace.real.buildMatrix(rowNum, colNum, initializer) @OptIn(UnstableKMathAPI::class) public fun realMatrix(rowNum: Int, colNum: Int): MatrixBuilder = - Double.algebra.linearSpace.matrix(rowNum, colNum) + LinearSpace.real.matrix(rowNum, colNum) public fun Array.toMatrix(): RealMatrix { - return Double.algebra.linearSpace.buildMatrix(size, this[0].size) { row, col -> this@toMatrix[row][col] } + return LinearSpace.real.buildMatrix(size, this[0].size) { row, col -> this@toMatrix[row][col] } } public fun Sequence.toMatrix(): RealMatrix = toList().let { - Double.algebra.linearSpace.buildMatrix(it.size, it[0].size) { row, col -> it[row][col] } + LinearSpace.real.buildMatrix(it.size, it[0].size) { row, col -> it[row][col] } } public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix = @@ -57,37 +52,37 @@ public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix = */ public operator fun RealMatrix.times(double: Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> get(row, col) * double } public operator fun RealMatrix.plus(double: Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> get(row, col) + double } public operator fun RealMatrix.minus(double: Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> get(row, col) - double } public operator fun RealMatrix.div(double: Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> get(row, col) / double } public operator fun Double.times(matrix: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@times * matrix[row, col] } public operator fun Double.plus(matrix: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@plus + matrix[row, col] } public operator fun Double.minus(matrix: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@minus - matrix[row, col] } @@ -102,20 +97,20 @@ public operator fun Double.minus(matrix: RealMatrix): RealMatrix = @UnstableKMathAPI public operator fun RealMatrix.times(other: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> this@times[row, col] * other[row, col] } + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> this@times[row, col] * other[row, col] } public operator fun RealMatrix.plus(other: RealMatrix): RealMatrix = - Double.algebra.linearSpace.run { this@plus + other } + LinearSpace.real.run { this@plus + other } public operator fun RealMatrix.minus(other: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> this@minus[row, col] - other[row, col] } + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> this@minus[row, col] - other[row, col] } /* * Operations on columns */ public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) -> Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum + 1) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum + 1) { row, col -> if (col < colNum) get(row, col) else @@ -123,7 +118,7 @@ public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) - } public fun RealMatrix.extractColumns(columnRange: IntRange): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, columnRange.count()) { row, col -> + LinearSpace.real.buildMatrix(rowNum, columnRange.count()) { row, col -> this@extractColumns[row, columnRange.first + col] } @@ -131,7 +126,7 @@ public fun RealMatrix.extractColumn(columnIndex: Int): RealMatrix = extractColumns(columnIndex..columnIndex) public fun RealMatrix.sumByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> - columns[j].sum() + columns[j].asIterable().sum() } public fun RealMatrix.minByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> @@ -156,14 +151,14 @@ public fun RealMatrix.max(): Double? = elements().map { (_, value) -> value }.ma public fun RealMatrix.average(): Double = elements().map { (_, value) -> value }.average() public inline fun RealMatrix.map(crossinline transform: (Double) -> Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { i, j -> + LinearSpace.real.buildMatrix(rowNum, colNum) { i, j -> transform(get(i, j)) } /** * Inverse a square real matrix using LUP decomposition */ -public fun RealMatrix.inverseWithLup(): RealMatrix = Double.algebra.linearSpace.lupSolver().inverse(this) +public fun RealMatrix.inverseWithLup(): RealMatrix = LinearSpace.real.inverseWithLup(this) //extended operations @@ -185,4 +180,4 @@ public fun tan(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.tan(it) } public fun ln(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.ln(it) } -public fun log10(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.log10(it) } +public fun log10(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.log10(it) } \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt similarity index 88% rename from kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt rename to kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt index 411a35188..d3867ea89 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt @@ -1,18 +1,20 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.real -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.linear.Point -import space.kscience.kmath.operations.DoubleL2Norm +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Norm import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer.Companion.double import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.fold import space.kscience.kmath.structures.indices import kotlin.math.pow +import kotlin.math.sqrt public typealias DoubleVector = Point @@ -20,7 +22,7 @@ public typealias DoubleVector = Point public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer() /** - * Fill the vector with given [size] with given [value] + * Fill the vector of given [size] with given [value] */ @UnstableKMathAPI public fun Buffer.Companion.same(size: Int, value: Number): DoubleVector = double(size) { value.toDouble() } @@ -103,4 +105,8 @@ public fun DoubleVector.sum(): Double { return res } -public val DoubleVector.norm: Double get() = DoubleL2Norm.norm(this) \ No newline at end of file +public object VectorL2Norm : Norm { + override fun norm(arg: DoubleVector): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) +} + +public val DoubleVector.norm: Double get() = VectorL2Norm.norm(this) \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt index 0c18602f1..b79e5030c 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt @@ -1,18 +1,17 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.real +import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.operations.algebra /** * Optimized dot product for real matrices */ -public infix fun Matrix.dot(other: Matrix): Matrix = Double.algebra.linearSpace.run { +public infix fun Matrix.dot(other: Matrix): Matrix = LinearSpace.real.run { this@dot dot other } \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt index adb62b173..c3556216d 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt @@ -1,11 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.real -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import kotlin.math.floor @@ -45,8 +45,8 @@ public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange.mapInline(crossinline transform: DoubleField.(Double) -> Double): BufferND { - val array = DoubleArray(indices.linearSize) { offset -> DoubleField.transform(buffer[offset]) } - return BufferND(indices, DoubleBuffer(array)) + val array = DoubleArray(strides.linearSize) { offset -> DoubleField.transform(buffer[offset]) } + return BufferND(strides, DoubleBuffer(array)) } /** diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt similarity index 89% rename from kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt rename to kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt index c00cd84d1..84e604b18 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleMatrixTest.kt @@ -1,22 +1,20 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.real +package kaceince.kmath.real -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.linear.linearSpace +import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.matrix +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.testutils.contentEquals +import space.kscience.kmath.real.* +import space.kscience.kmath.structures.contentEquals import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -@OptIn(PerformancePitfall::class) fun assertMatrixEquals(expected: StructureND, actual: StructureND) { assertTrue { StructureND.contentEquals(expected, actual) } } @@ -32,7 +30,7 @@ internal class DoubleMatrixTest { @Test fun testSequenceToMatrix() { - val m = Sequence { + val m = Sequence { listOf( DoubleArray(10) { 10.0 }, DoubleArray(10) { 20.0 }, @@ -59,13 +57,13 @@ internal class DoubleMatrixTest { } @Test - fun testMatrixAndDouble() = Double.algebra.linearSpace.run { + fun testMatrixAndDouble() { val matrix1 = realMatrix(2, 3)( 1.0, 0.0, 3.0, 4.0, 6.0, 2.0 ) val matrix2 = (matrix1 * 2.5 + 1.0 - 2.0) / 2.0 - val expectedResult = matrix(2, 3)( + val expectedResult = LinearSpace.real.matrix(2, 3)( 0.75, -0.5, 3.25, 4.5, 7.0, 2.0 ) @@ -159,8 +157,8 @@ internal class DoubleMatrixTest { } @Test - fun testAllElementOperations() = Double.algebra.linearSpace.run { - val matrix1 = matrix(2, 4)( + fun testAllElementOperations() { + val matrix1 = LinearSpace.real.matrix(2, 4)( -1.0, 0.0, 3.0, 15.0, 4.0, -6.0, 7.0, -11.0 ) diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt similarity index 80% rename from kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt rename to kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt index a25091ac2..9de54381c 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt @@ -1,14 +1,14 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.real +package kaceince.kmath.real +import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.asMatrix -import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.transpose -import space.kscience.kmath.operations.algebra +import space.kscience.kmath.real.plus import space.kscience.kmath.structures.DoubleBuffer import kotlin.test.Test import kotlin.test.assertEquals @@ -30,12 +30,12 @@ internal class DoubleVectorTest { } @Test - fun testDot() = Double.algebra.linearSpace.run { + fun testDot() { val vector1 = DoubleBuffer(5) { it.toDouble() } val vector2 = DoubleBuffer(5) { 5 - it.toDouble() } val matrix1 = vector1.asMatrix() val matrix2 = vector2.asMatrix().transpose() - val product = matrix1 dot matrix2 + val product = LinearSpace.real.run { matrix1 dot matrix2 } assertEquals(5.0, product[1, 0]) assertEquals(6.0, product[2, 2]) } diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/GridTest.kt similarity index 68% rename from kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt rename to kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/GridTest.kt index 35c53f9d6..0d3b80336 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/GridTest.kt @@ -1,11 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.real +package kaceince.kmath.real -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.real.DoubleVector +import space.kscience.kmath.real.minus +import space.kscience.kmath.real.norm +import space.kscience.kmath.real.step import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 929fd9172..eef677565 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,27 +11,29 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.4.0-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-6`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } - mavenCentral() + maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap } dependencies { - implementation 'space.kscience:kmath-functions:0.4.0-dev-1' + implementation 'space.kscience:kmath-functions:0.3.0-dev-6' } ``` **Gradle Kotlin DSL:** ```kotlin repositories { maven("https://repo.kotlin.link") - mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap + maven("https://dl.bintray.com/hotkeytlt/maven") // required for a } dependencies { - implementation("space.kscience:kmath-functions:0.4.0-dev-1") + implementation("space.kscience:kmath-functions:0.3.0-dev-6") } ``` diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index acabd1eb9..ca678bc0e 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -1,43 +1,22 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + plugins { - id("space.kscience.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") } -kscience{ - jvm() - js() - native() - - wasm{ - browser { - testTask { - useKarma { - this.webpackConfig.experiments.add("topLevelAwait") - useChromeHeadless() - useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm")) - } - } - } - } - - wasmTest{ - dependencies { - implementation(kotlin("test")) - } - } - +kotlin.sourceSets.commonMain { dependencies { - api(projects.kmathCore) + api(project(":kmath-core")) } } -description = "Functions, integration and interpolation" - -dependencies { - dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${spclibs.versions.dokka.get()}") -} - readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + description = "Functions, integration and interpolation" + maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature("piecewise", "src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt") { @@ -55,4 +34,4 @@ readme { feature("integration") { "Univariate and multivariate quadratures" } -} +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index a9e75e456..6d481e334 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -1,11 +1,10 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.functions -import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.operations.Ring /** @@ -14,7 +13,7 @@ import space.kscience.kmath.operations.Ring * @param T the piece key type. * @param R the sub-function type. */ -public fun interface Piecewise { +public fun interface Piecewise { /** * Returns the appropriate sub-function for given piece key. */ @@ -23,63 +22,23 @@ public fun interface Piecewise { /** * Represents piecewise-defined function where all the sub-functions are polynomials. - * - * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no - * "holes" in it. */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, Polynomial>> - - override fun findPiece(arg: T): Polynomial? -} +public fun interface PiecewisePolynomial : Piecewise> /** - * A generic piecewise without constraints on how pieces are placed - */ -@PerformancePitfall("findPiece method of resulting piecewise is slow") -public fun > PiecewisePolynomial( - pieces: Collection, Polynomial>>, -): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, Polynomial>> = pieces - - override fun findPiece(arg: T): Polynomial? = pieces.firstOrNull { arg in it.first }?.second -} - -/** - * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. - * The pieces search is logarithmic. - */ -private class OrderedPiecewisePolynomial>( - override val pieces: List, Polynomial>>, -) : PiecewisePolynomial { - - override fun findPiece(arg: T): Polynomial? { - val index = pieces.binarySearch { (range, _) -> - when { - arg >= range.endInclusive -> -1 - arg < range.start -> +1 - else -> 0 - } - } - return if (index < 0) null else pieces[index].second - } - -} - -/** - * A [Piecewise] builder where all the pieces are ordered by the [Comparable] type instances. + * Basic [Piecewise] implementation where all the pieces are ordered by the [Comparable] type instances. * * @param T the comparable piece key type. - * @param delimiter the initial piecewise separator */ -public class PiecewiseBuilder>(delimiter: T) { +public class OrderedPiecewisePolynomial>(delimiter: T) : + PiecewisePolynomial { private val delimiters: MutableList = arrayListOf(delimiter) private val pieces: MutableList> = arrayListOf() /** * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) * - * @param right new rightmost position. If is less than current rightmost position, an error is thrown. + * @param right new rightmost position. If is less then current rightmost position, an error is thrown. * @param piece the sub-function. */ public fun putRight(right: T, piece: Polynomial) { @@ -91,7 +50,7 @@ public class PiecewiseBuilder>(delimiter: T) { /** * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) * - * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. + * @param left the new leftmost position. If is less then current rightmost position, an error is thrown. * @param piece the sub-function. */ public fun putLeft(left: T, piece: Polynomial) { @@ -100,33 +59,24 @@ public class PiecewiseBuilder>(delimiter: T) { pieces.add(0, piece) } - public fun build(): PiecewisePolynomial = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r -> - l..r - }.zip(pieces)) + public override fun findPiece(arg: T): Polynomial? { + if (arg < delimiters.first() || arg >= delimiters.last()) + return null + else { + for (index in 1 until delimiters.size) + if (arg < delimiters[index]) + return pieces[index - 1] + + error("Piece not found") + } + } } /** - * A builder for [PiecewisePolynomial] - */ -public fun > PiecewisePolynomial( - startingPoint: T, - builder: PiecewiseBuilder.() -> Unit, -): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() - -/** - * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise + * Return a value of polynomial function with given [ring] an given [arg] or null if argument is outside of piecewise * definition. */ public fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = findPiece(arg)?.value(ring, arg) -/** - * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). - */ public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } - -/** - * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { value(ring, it) ?: defaultValue } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index af84f47f2..efae71b0e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -1,280 +1,95 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") - package space.kscience.kmath.functions +import space.kscience.kmath.operations.Group import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.math.max -import kotlin.math.min - +import kotlin.math.pow /** - * Represents univariate polynomial that stores its coefficients in a [List]. + * Polynomial coefficients model without fixation on specific context they are applied to. * - * @param C the type of constants. + * @param coefficients constant is the leftmost coefficient. */ -public data class Polynomial( - /** - * List that contains coefficients of the polynomial. - * - * Every monomial \(a x^d\) is stored as a coefficient \(a\) placed - * into the list at index \(d\). For example, coefficients of a polynomial \(5 x^2 - 6\) can be represented as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * ) - * ``` - * and also as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * 0, // 0 x^3 - * 0, // 0 x^4 - * ) - * ``` - * It is not prohibited to put extra zeros at end of the list (as for \(0x^3\) and \(0x^4\) in the example). But the - * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is - * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. - * - * @usesMathJax - */ - public val coefficients: List -) { - override fun toString(): String = "Polynomial$coefficients" +public class Polynomial(public val coefficients: List) + +/** + * Returns a [Polynomial] instance with given [coefficients]. + */ +@Suppress("FunctionName") +public fun Polynomial(vararg coefficients: T): Polynomial = Polynomial(coefficients.toList()) + +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun Polynomial.value(): Double = coefficients.reduceIndexed { index, acc, d -> acc + d.pow(index) } + +/** + * Evaluates the value of the given polynomial for given argument. + */ +public fun > Polynomial.value(ring: C, arg: T): T = ring { + if (coefficients.isEmpty()) return@ring zero + var res = coefficients.first() + var powerArg = arg + + for (index in 1 until coefficients.size) { + res += coefficients[index] * powerArg + // recalculating power on each step to avoid power costs on long polynomials + powerArg *= arg + } + + res } /** - * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided - * [ring] of constants. - * - * @param C the type of constants. Polynomials have them a coefficients in their terms. - * @param A type of provided underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. + * Represent the polynomial as a regular context-less function. */ -public open class PolynomialSpace( - /** - * Underlying ring of constants. Its operations on constants are used by local operations on constants and polynomials. - */ - public val ring: A, -) : Ring>, ScaleOperations> where A : Ring, A : ScaleOperations { +public fun > Polynomial.asFunction(ring: C): (T) -> T = { value(ring, it) } - /** - * Instance of zero constant (zero of the underlying ring). - */ - public val constantZero: C get() = ring.zero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public val constantOne: C get() = ring.one +/** + * Space of polynomials. + * + * @param T the type of operated polynomials. + * @param C the intersection of [Ring] of [T] and [ScaleOperations] of [T]. + * @param ring the [C] instance. + */ +public class PolynomialSpace( + private val ring: C, +) : Group>, ScaleOperations> where C : Ring, C : ScaleOperations { + public override val zero: Polynomial = Polynomial(emptyList()) - /** - * Returns sum of the constant represented as a polynomial and the polynomial. - */ - public operator fun C.plus(other: Polynomial): Polynomial = - with(ring) { - with(other.coefficients) { - if (isEmpty()) Polynomial(listOf(this@plus)) - else Polynomial( - toMutableList() - .apply { - val result = if (size == 0) this@plus else this@plus + get(0) - - if (size == 0) add(result) - else this[0] = result - } - ) - } - } - /** - * Returns difference between the constant represented as a polynomial and the polynomial. - */ - public operator fun C.minus(other: Polynomial): Polynomial = - with(ring) { - with(other.coefficients) { - if (isEmpty()) Polynomial(listOf(this@minus)) - else Polynomial( - toMutableList() - .apply { - (1..lastIndex).forEach { this[it] = -this[it] } - - val result = if (size == 0) this@minus else this@minus - get(0) - - if (size == 0) add(result) - else this[0] = result - } - ) - } - } - /** - * Returns product of the constant represented as a polynomial and the polynomial. - */ - public operator fun C.times(other: Polynomial): Polynomial = - with(ring) { - Polynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) - } - - /** - * Returns sum of the constant represented as a polynomial and the polynomial. - */ - public operator fun Polynomial.plus(other: C): Polynomial = - with(ring) { - with(coefficients) { - if (isEmpty()) Polynomial(listOf(other)) - else Polynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) + other - - if (size == 0) add(result) - else this[0] = result - } - ) - } - } - /** - * Returns difference between the constant represented as a polynomial and the polynomial. - */ - public operator fun Polynomial.minus(other: C): Polynomial = - with(ring) { - with(coefficients) { - if (isEmpty()) Polynomial(listOf(-other)) - else Polynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) - other - - if (size == 0) add(result) - else this[0] = result - } - ) - } - } - /** - * Returns product of the constant represented as a polynomial and the polynomial. - */ - public operator fun Polynomial.times(other: C): Polynomial = - with(ring) { - Polynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) - } - - /** - * Converts the constant [value] to polynomial. - */ - public fun number(value: C): Polynomial = Polynomial(listOf(value)) - /** - * Converts the constant to polynomial. - */ - public fun C.asPolynomial(): Polynomial = number(this) - - /** - * Returns negation of the polynomial. - */ - public override operator fun Polynomial.unaryMinus(): Polynomial = ring { + override fun Polynomial.unaryMinus(): Polynomial = ring { Polynomial(coefficients.map { -it }) } - /** - * Returns sum of the polynomials. - */ - public override operator fun Polynomial.plus(other: Polynomial): Polynomial = ring { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } - } - ) - } - /** - * Returns difference of the polynomials. - */ - public override operator fun Polynomial.minus(other: Polynomial): Polynomial = ring { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> -other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } - } - ) - } - /** - * Returns product of the polynomials. - */ - public override operator fun Polynomial.times(other: Polynomial): Polynomial = ring { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - List(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) + + public override fun add(a: Polynomial, b: Polynomial): Polynomial { + val dim = max(a.coefficients.size, b.coefficients.size) + + return ring { + Polynomial(List(dim) { index -> + a.coefficients.getOrElse(index) { zero } + b.coefficients.getOrElse(index) { zero } + }) + } } - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: Polynomial = Polynomial(emptyList()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: Polynomial by lazy { Polynomial(listOf(constantOne)) } + public override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. + * Evaluates the polynomial for the given value [arg]. */ - public val Polynomial.degree: Int get() = coefficients.lastIndex - - override fun add(left: Polynomial, right: Polynomial): Polynomial = left + right - override fun multiply(left: Polynomial, right: Polynomial): Polynomial = left * right - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(a.coefficients.map { scale(it, value) }) } - - // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with - // [ListPolynomialSpace] as a context receiver - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline fun Polynomial.substitute(argument: C): C = value(ring, argument) - - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun Polynomial.asFunction(): (C) -> C = asFunctionOver(ring) - - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline operator fun Polynomial.invoke(argument: C): C = value(ring, argument) + public operator fun Polynomial.invoke(arg: T): T = value(ring, arg) +} + +public inline fun C.polynomial(block: PolynomialSpace.() -> R): R where C : Ring, C : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return PolynomialSpace(this).block() } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt index c2f95f040..88b24c756 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,6 +7,6 @@ package space.kscience.kmath.functions import space.kscience.kmath.structures.Buffer -public typealias Function1D = (T) -> T +public typealias UnivariateFunction = (T) -> T -public typealias FunctionND = (Buffer) -> T \ No newline at end of file +public typealias MultivariateFunction = (Buffer) -> T \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt deleted file mode 100644 index 4e9791a87..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - - -/** - * Constructs a [Polynomial] instance with provided [coefficients]. The collection of coefficients will be reversed - * if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = - Polynomial(with(coefficients) { if (reverse) reversed() else this }) - -/** - * Constructs a [Polynomial] instance with provided [coefficients]. The collection of coefficients will be reversed - * if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = - Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -/** - * Represents [this] constant as a [Polynomial]. - */ -public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt deleted file mode 100644 index 0d4b93f03..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max -import kotlin.math.pow - - -/** - * Creates a [PolynomialSpace] over a received ring. - */ -public inline val A.polynomialSpace: PolynomialSpace where A : Ring, A : ScaleOperations - get() = PolynomialSpace(this) - -/** - * Creates a [PolynomialSpace]'s scope over a received ring. - */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun A.polynomialSpace(block: PolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return PolynomialSpace(this).block() -} - - -/** - * Evaluates value of [this] Double polynomial on provided Double argument. - */ -public fun Polynomial.value(arg: Double): Double = - coefficients.reduceIndexedOrNull { index, acc, c -> - acc + c * arg.pow(index) - } ?: .0 - -/** - * Evaluates value of [this] polynomial on provided argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun Polynomial.value(ring: Ring, arg: C): C = ring { - if (coefficients.isEmpty()) return zero - var result: C = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > Polynomial.asFunctionOver(ring: A): (C) -> C = { value(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun Polynomial.differentiate( - ring: A, -): Polynomial where A : Ring, A : NumericAlgebra = ring { - Polynomial( - buildList(max(0, coefficients.size - 1)) { - for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun Polynomial.integrate( - ring: A, -): Polynomial where A : Field, A : NumericAlgebra = ring { - Polynomial( - buildList(coefficients.size + 1) { - add(zero) - coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - } - ) -} - -/** - * Computes a definite integral of [this] polynomial in the specified [range]. - */ -@UnstableKMathAPI -public fun > Polynomial.integrate( - ring: Field, - range: ClosedRange, -): C = ring { - val antiderivative = integrate(ring) - return antiderivative.value(ring, range.endInclusive) - antiderivative.value(ring, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt index f2ac0a296..bc23e2f1b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt @@ -1,26 +1,16 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.integration -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.indices +import space.kscience.kmath.structures.* + /** * A simple one-pass integrator based on Gauss rule - * Following integrand features are accepted: - * - * * [GaussIntegratorRuleFactory]—a factory for computing the Gauss integration rule. By default, uses - * [GaussLegendreRuleFactory]. - * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always - * uses the maximum number of points. By default, uses 10 points. - * * [UnivariateIntegrandRanges]—set of ranges and number of points per range. Defaults to given - * [IntegrationRange] and [IntegrandMaxCalls]. */ public class GaussIntegrator( public val algebra: Field, @@ -28,32 +18,12 @@ public class GaussIntegrator( private fun buildRule(integrand: UnivariateIntegrand): Pair, Buffer> { val factory = integrand.getFeature() ?: GaussLegendreRuleFactory - val predefinedRanges = integrand.getFeature() - if (predefinedRanges == null || predefinedRanges.ranges.isEmpty()) { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val range = integrand.getFeature()?.range ?: 0.0..1.0 - return factory.build(numPoints, range) - } else { - val ranges = predefinedRanges.ranges - var counter = 0 - val length = ranges.sumOf { it.second } - val pointsArray = DoubleArray(length) - val weightsArray = DoubleArray(length) - - for (range in ranges) { - val rule = factory.build(range.second, range.first) - repeat(rule.first.size) { i -> - pointsArray[counter] = rule.first[i] - weightsArray[counter] = rule.second[i] - counter++ - } - - } - return pointsArray.asBuffer() to weightsArray.asBuffer() - } + val numPoints = integrand.getFeature()?.maxCalls ?: 100 + val range = integrand.getFeature>()?.range ?: 0.0..1.0 + return factory.build(numPoints, range) } - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = with(algebra) { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand = with(algebra) { val f = integrand.function val (points, weights) = buildRule(integrand) var res = zero @@ -69,42 +39,40 @@ public class GaussIntegrator( return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + points.size) } - public companion object + public companion object { + + } } /** - * Create a Gauss integrator for this field. By default, uses Legendre rule to compute points and weights. - * Custom rules could be provided by [GaussIntegratorRuleFactory] feature. - * @see [GaussIntegrator] + * Integrate [T]-valued univariate function using provided set of [IntegrandFeature] + * Following features are evaluated: + * * [GaussIntegratorRuleFactory] - A factory for computing the Gauss integration rule. By default uses [GaussLegendreRuleFactory] + * * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. + * * [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 100 points. */ -public val Field.gaussIntegrator: GaussIntegrator get() = GaussIntegrator(this) +@UnstableKMathAPI +public fun Field.integrate( + vararg features: IntegrandFeature, + function: (Double) -> T, +): UnivariateIntegrand = GaussIntegrator(this).integrate(UnivariateIntegrand(function, *features)) /** - * Integrate using [intervals] segments with Gauss-Legendre rule of [order] order. + * Use [GaussIntegrator.Companion.integrate] to integrate the function in the current algebra with given [range] and [numPoints] */ @UnstableKMathAPI -public fun GaussIntegrator.integrate( +public fun Field.integrate( range: ClosedRange, - order: Int = 10, - intervals: Int = 10, + numPoints: Int = 100, vararg features: IntegrandFeature, function: (Double) -> T, -): UnivariateIntegrand { - require(range.endInclusive > range.start) { "The range upper bound should be higher than lower bound" } - require(order > 1) { "The order of polynomial must be more than 1" } - require(intervals > 0) { "Number of intervals must be positive" } - val rangeSize = (range.endInclusive - range.start) / intervals - val ranges = UnivariateIntegrandRanges( - (0 until intervals).map { i -> (range.start + rangeSize * i)..(range.start + rangeSize * (i + 1)) to order } +): UnivariateIntegrand = GaussIntegrator(this).integrate( + UnivariateIntegrand( + function, + IntegrationRange(range), + GaussLegendreRuleFactory, + IntegrandMaxCalls(numPoints), + *features ) - return process( - UnivariateIntegrand( - function, - IntegrationRange(range), - GaussLegendreRuleFactory, - ranges, - *features - ) - ) -} \ No newline at end of file +) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt index 4ed4965c9..133f829e3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt @@ -1,14 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.integration -import space.kscience.kmath.operations.mapToBuffer import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.map +import kotlin.jvm.Synchronized import kotlin.math.ulp import kotlin.native.concurrent.ThreadLocal @@ -29,14 +30,14 @@ public fun GaussIntegratorRuleFactory.build( numPoints: Int, range: ClosedRange, ): Pair, Buffer> { - val normalized: Pair, Buffer> = build(numPoints) + val normalized = build(numPoints) val length = range.endInclusive - range.start - val points = normalized.first.mapToBuffer(::DoubleBuffer) { + val points = normalized.first.map(::DoubleBuffer) { range.start + length / 2 + length / 2 * it } - val weights = normalized.second.mapToBuffer(::DoubleBuffer) { + val weights = normalized.second.map(::DoubleBuffer) { it * length / 2 } @@ -56,6 +57,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { private val cache = HashMap, Buffer>>() + @Synchronized private fun getOrBuildRule(numPoints: Int): Pair, Buffer> = cache.getOrPut(numPoints) { buildRule(numPoints) } @@ -70,7 +72,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { } // Get previous rule. - // If it has not been computed, yet it will trigger a recursive call + // If it has not been computed yet it will trigger a recursive call // to this method. val previousPoints: Buffer = getOrBuildRule(numPoints - 1).first @@ -144,7 +146,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { } // If "numPoints" is odd, 0 is a root. // Note: as written, the test for oddness will work for negative - // integers too (although it is unnecessary here), preventing + // integers too (although it is not necessary here), preventing // a FindBugs warning. if (numPoints % 2 != 0) { var pmc = 1.0 @@ -162,6 +164,4 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { } override fun build(numPoints: Int): Pair, Buffer> = getOrBuildRule(numPoints) - - override fun toString(): String = "GaussLegendreRule" } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt index 40fe78898..1ff8e422e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt @@ -1,48 +1,28 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.integration -import space.kscience.kmath.misc.Feature -import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.misc.Featured import kotlin.reflect.KClass -public interface IntegrandFeature : Feature { - override fun toString(): String -} +public interface IntegrandFeature -public interface Integrand : Featured { - public val features: FeatureSet - override fun getFeature(type: KClass): T? = features.getFeature(type) +public interface Integrand { + public fun getFeature(type: KClass): T? } public inline fun Integrand.getFeature(): T? = getFeature(T::class) -public class IntegrandValue(public val value: T) : IntegrandFeature { - override fun toString(): String = "Value($value)" -} +public class IntegrandValue(public val value: T) : IntegrandFeature -public class IntegrandRelativeAccuracy(public val accuracy: Double) : IntegrandFeature { - override fun toString(): String = "TargetRelativeAccuracy($accuracy)" -} +public class IntegrandRelativeAccuracy(public val accuracy: Double) : IntegrandFeature -public class IntegrandAbsoluteAccuracy(public val accuracy: Double) : IntegrandFeature { - override fun toString(): String = "TargetAbsoluteAccuracy($accuracy)" -} +public class IntegrandAbsoluteAccuracy(public val accuracy: Double) : IntegrandFeature -public class IntegrandCallsPerformed(public val calls: Int) : IntegrandFeature { - override fun toString(): String = "Calls($calls)" -} +public class IntegrandCallsPerformed(public val calls: Int) : IntegrandFeature public val Integrand.calls: Int get() = getFeature()?.calls ?: 0 -public class IntegrandMaxCalls(public val maxCalls: Int) : IntegrandFeature { - override fun toString(): String = "MaxCalls($maxCalls)" -} - -public class IntegrandIterationsRange(public val range: IntRange) : IntegrandFeature { - override fun toString(): String = "Iterations(${range.first}..${range.last})" -} +public class IntegrandMaxCalls(public val maxCalls: Int) : IntegrandFeature diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt index 18c46b83b..abe6ea5ff 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -12,5 +12,5 @@ public interface Integrator { /** * Runs one integration pass and return a new [Integrand] with a new set of features. */ - public fun process(integrand: I): I + public fun integrate(integrand: I): I } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt index 53a563086..12d0ef0a6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt @@ -1,26 +1,32 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.integration import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.FeatureSet +import kotlin.reflect.KClass public class MultivariateIntegrand internal constructor( - override val features: FeatureSet, + private val features: Map, IntegrandFeature>, public val function: (Point) -> T, ) : Integrand { + @Suppress("UNCHECKED_CAST") + override fun getFeature(type: KClass): T? = features[type] as? T + + public operator fun plus(pair: Pair, F>): MultivariateIntegrand = + MultivariateIntegrand(features + pair, function) + public operator fun plus(feature: F): MultivariateIntegrand = - MultivariateIntegrand(features.with(feature), function) + plus(feature::class to feature) } @Suppress("FunctionName") public fun MultivariateIntegrand( vararg features: IntegrandFeature, function: (Point) -> T, -): MultivariateIntegrand = MultivariateIntegrand(FeatureSet.of(*features), function) +): MultivariateIntegrand = MultivariateIntegrand(features.associateBy { it::class }, function) public val MultivariateIntegrand.value: T? get() = getFeature>()?.value diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt deleted file mode 100644 index 73a3cc25b..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.sum - -/** - * Use double pass Simpson rule integration with a fixed number of points. - * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls]. - * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always - * uses the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public class SimpsonIntegrator( - public val algebra: Field, -) : UnivariateIntegrator { - - private fun integrateRange( - integrand: UnivariateIntegrand, range: ClosedRange, numPoints: Int, - ): T = algebra { - val h: Double = (range.endInclusive - range.start) / (numPoints - 1) - val values: List = List(numPoints) { i -> - integrand.function(range.start + i * h) - }// equally distributed point - - //TODO don't use list, reassign values instead - fun simpson(index: Int) = h / 3 * (values[index - 1] + 4 * values[index] + values[index + 1]) - - var res = zero - res += simpson(1) / 1.5 //border points with 1.5 factor - for (i in 2 until (values.size - 2)) { - //each half-interval is computed twice, therefore /2 - res += simpson(i) / 2 - } - res += simpson(values.size - 2) / 1.5 //border points with 1.5 factor - return res - } - - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { - val ranges = integrand.getFeature() - return if (ranges != null) { - val res = algebra.sum(ranges.ranges.map { integrateRange(integrand, it.first, it.second) }) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second }) - } else { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - require(numPoints >= 4) { "Simpson integrator requires at least 4 nodes" } - val range = integrand.getFeature()?.range ?: 0.0..1.0 - val res = integrateRange(integrand, range, numPoints) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numPoints) - } - } -} - -@UnstableKMathAPI -public val Field.simpsonIntegrator: SimpsonIntegrator get() = SimpsonIntegrator(this) - -/** - * Use double pass Simpson rule integration with a fixed number of points. - * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls]. - * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses - * the maximum number of points. By default, uses 10 points. - */ -public object DoubleSimpsonIntegrator : UnivariateIntegrator { - private fun integrateRange( - integrand: UnivariateIntegrand, range: ClosedRange, numPoints: Int, - ): Double { - val h: Double = (range.endInclusive - range.start) / (numPoints - 1) - val values = DoubleArray(numPoints) { i -> - integrand.function(range.start + i * h) - }// equally distributed point - - fun simpson(index: Int) = h / 3 * (values[index - 1] + 4 * values[index] + values[index + 1]) - - var res = 0.0 - res += simpson(1) / 1.5 //border points with 1.5 factor - for (i in 2 until (values.size - 2)) { - //each half-interval is computed twice, therefore /2 - res += simpson(i) / 2 - } - res += simpson(values.size - 2) / 1.5 //border points with 1.5 factor - return res - } - - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { - val ranges = integrand.getFeature() - return if (ranges != null) { - val res = ranges.ranges.sumOf { integrateRange(integrand, it.first, it.second) } - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second }) - } else { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - require(numPoints >= 4) { "Simpson integrator requires at least 4 nodes" } - val range = integrand.getFeature()?.range ?: 0.0..1.0 - val res = integrateRange(integrand, range, numPoints) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numPoints) - } - } -} - -public val DoubleField.simpsonIntegrator: DoubleSimpsonIntegrator get() = DoubleSimpsonIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt deleted file mode 100644 index 993812b29..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.interpolation.PolynomialInterpolator -import space.kscience.kmath.interpolation.SplineInterpolator -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact - */ -@OptIn(PerformancePitfall::class) -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) - -/** - * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] - * Requires [UnivariateIntegrationNodes] or [IntegrationRange] and [IntegrandMaxCalls] - * - * TODO use context receiver for algebra - */ -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate( - algebra: Field, range: ClosedRange, -): T = algebra.sum( - pieces.map { (region, poly) -> - val intersectedRange = maxOf(range.start, region.start)..minOf(range.endInclusive, region.endInclusive) - //Check if polynomial range is not used - if (intersectedRange.start == intersectedRange.endInclusive) algebra.zero - else poly.integrate(algebra, intersectedRange) - } -) - -/** - * A generic spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses - * the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public class SplineIntegrator>( - public val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - - val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.mapToBuffer(bufferFactory) { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials( - nodes.mapToBuffer(bufferFactory) { number(it) }, - values - ) - val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive)) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -/** - * A simplified double-based spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always - * uses the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public object DoubleSplineIntegrator : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.mapToBuffer(::DoubleBuffer) { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials(nodes, values) - val res = polynomials.integrate(DoubleField, range) - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -@Suppress("unused") -@UnstableKMathAPI -public inline val DoubleField.splineIntegrator: UnivariateIntegrator - get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt index f18e86b80..0b41a3f8b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt @@ -1,102 +1,71 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.integration -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.misc.UnstableKMathAPI +import kotlin.jvm.JvmInline +import kotlin.reflect.KClass -public class UnivariateIntegrand internal constructor( - override val features: FeatureSet, +public class UnivariateIntegrand internal constructor( + private val features: Map, IntegrandFeature>, public val function: (Double) -> T, ) : Integrand { + + @Suppress("UNCHECKED_CAST") + override fun getFeature(type: KClass): T? = features[type] as? T + + public operator fun plus(pair: Pair, F>): UnivariateIntegrand = + UnivariateIntegrand(features + pair, function) + public operator fun plus(feature: F): UnivariateIntegrand = - UnivariateIntegrand(features.with(feature), function) + plus(feature::class to feature) } @Suppress("FunctionName") public fun UnivariateIntegrand( function: (Double) -> T, vararg features: IntegrandFeature, -): UnivariateIntegrand = UnivariateIntegrand(FeatureSet.of(*features), function) +): UnivariateIntegrand = UnivariateIntegrand(features.associateBy { it::class }, function) public typealias UnivariateIntegrator = Integrator> -public class IntegrationRange(public val range: ClosedRange) : IntegrandFeature { - override fun toString(): String = "Range(${range.start}..${range.endInclusive})" -} +@JvmInline +public value class IntegrationRange>(public val range: ClosedRange) : IntegrandFeature -/** - * Set of univariate integration ranges. First components correspond to the ranges themselves, second components to - * number of integration nodes per range. - */ -public class UnivariateIntegrandRanges(public val ranges: List, Int>>) : IntegrandFeature { - public constructor(vararg pairs: Pair, Int>) : this(pairs.toList()) - - override fun toString(): String { - val rangesString = ranges.joinToString(separator = ",") { (range, points) -> - "${range.start}..${range.endInclusive} : $points" - } - return "UnivariateRanges($rangesString)" - } -} - -public class UnivariateIntegrationNodes(public val nodes: Buffer) : IntegrandFeature { - public constructor(vararg nodes: Double) : this(DoubleBuffer(nodes)) - - override fun toString(): String = "UnivariateNodes($nodes)" -} - - -/** - * Value of the integrand if it is present or null - */ -public val UnivariateIntegrand.valueOrNull: T? get() = getFeature>()?.value - -/** - * Value of the integrand or error - */ -public val UnivariateIntegrand.value: T get() = valueOrNull ?: error("No value in the integrand") - -/** - * A shortcut method to integrate a [function] with additional [features]. Range must be provided in features. - * The [function] is placed in the end position to allow passing a lambda. - */ -@UnstableKMathAPI -public fun UnivariateIntegrator.integrate( - vararg features: IntegrandFeature, - function: (Double) -> T, -): UnivariateIntegrand = process(UnivariateIntegrand(function, *features)) +public val UnivariateIntegrand.value: T? get() = getFeature>()?.value /** * A shortcut method to integrate a [function] in [range] with additional [features]. * The [function] is placed in the end position to allow passing a lambda. */ @UnstableKMathAPI -public fun UnivariateIntegrator.integrate( +public fun UnivariateIntegrator.integrate( range: ClosedRange, vararg features: IntegrandFeature, - function: (Double) -> T, -): UnivariateIntegrand = process(UnivariateIntegrand(function, IntegrationRange(range), *features)) + function: (Double) -> Double, +): Double = integrate( + UnivariateIntegrand(function, IntegrationRange(range), *features) +).value ?: error("Unexpected: no value after integration.") /** - * A shortcut method to integrate a [function] in [range] with additional features. + * A shortcut method to integrate a [function] in [range] with additional [features]. * The [function] is placed in the end position to allow passing a lambda. */ @UnstableKMathAPI -public fun UnivariateIntegrator.integrate( +public fun UnivariateIntegrator.integrate( range: ClosedRange, - featureBuilder: MutableList.() -> Unit = {}, - function: (Double) -> T, -): UnivariateIntegrand { + function: (Double) -> Double, + featureBuilder: (MutableList.() -> Unit) = {}, +): Double { //TODO use dedicated feature builder class instead or add extensions to MutableList val features = buildList { featureBuilder() add(IntegrationRange(range)) } - return process(UnivariateIntegrand(function, *features.toTypedArray())) + return integrate( + UnivariateIntegrand(function, *features.toTypedArray()) + ).value ?: error("Unexpected: no value after integration.") } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index 191e7dfd9..08090a522 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,25 +7,18 @@ package space.kscience.kmath.interpolation -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction import space.kscience.kmath.functions.value +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer -/** - * And interpolator for data with x column type [X], y column type [Y]. - */ -public fun interface Interpolator { +public fun interface Interpolator { public fun interpolate(points: XYColumnarData): (X) -> Y } -/** - * And interpolator returning [PiecewisePolynomial] function - */ public interface PolynomialInterpolator> : Interpolator { public val algebra: Ring @@ -43,50 +36,20 @@ public fun > PolynomialInterpolator.interpolatePolynomials( x: Buffer, y: Buffer, ): PiecewisePolynomial { - val pointSet = XYColumnarData.of(x, y) + val pointSet = XYColumnarData(x, y) return interpolatePolynomials(pointSet) } public fun > PolynomialInterpolator.interpolatePolynomials( data: Map, ): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) + val pointSet = XYColumnarData(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) return interpolatePolynomials(pointSet) } public fun > PolynomialInterpolator.interpolatePolynomials( data: List>, ): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) + val pointSet = XYColumnarData(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) return interpolatePolynomials(pointSet) } - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, -): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: Map, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: List>, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, - defaultValue: T, -): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: Map, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: List>, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt index 5c56e406a..3fbf6157e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -1,14 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.interpolation -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.OrderedPiecewisePolynomial import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.Polynomial +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.invoke @@ -21,14 +22,13 @@ internal fun > insureSorted(points: XYColumnarData<*, T, *>) { /** * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java */ -public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { - +public class LinearInterpolator>(public override val algebra: Field) : PolynomialInterpolator { @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + public override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { require(points.size > 0) { "Point array should not be empty" } insureSorted(points) - PiecewisePolynomial(points.x[0]) { + OrderedPiecewisePolynomial(points.x[0]).apply { for (i in 0 until points.size - 1) { val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) val const = points.y[i] - slope * points.x[i] @@ -38,6 +38,3 @@ public class LinearInterpolator>(override val algebra: Field> Field.linearInterpolator: LinearInterpolator - get() = LinearInterpolator(this) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt index a3cc17954..f00b66a4c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -1,18 +1,17 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.interpolation -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.OrderedPiecewisePolynomial import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.MutableBufferFactory /** @@ -23,33 +22,34 @@ import space.kscience.kmath.structures.MutableBufferFactory * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java */ public class SplineInterpolator>( - override val algebra: Field, + public override val algebra: Field, public val bufferFactory: MutableBufferFactory, ) : PolynomialInterpolator { //TODO possibly optimize zeroed buffers @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + public override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } insureSorted(points) // Number of intervals. The number of data points is n + 1. val n = points.size - 1 // Differences between knot points - val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] } - val mu = bufferFactory(n) { zero } - val z = bufferFactory(n + 1) { zero } + val h = bufferFactory(points.size) { i -> points.x[i + 1] - points.x[i] } + val mu = bufferFactory(points.size - 1) { zero } + val z = bufferFactory(points.size) { zero } for (i in 1 until n) { val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] mu[i] = h[i] / g + z[i] = - ((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 / - (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g + (3.0 * (points.y[i + 1] * h[i - 1] - points.x[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) / (h[i - 1] * h[i]) + - h[i - 1] * z[i - 1]) / g } // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) - PiecewisePolynomial(points.x[points.size - 1]) { + OrderedPiecewisePolynomial(points.x[points.size - 1]).apply { var cOld = zero for (j in n - 1 downTo 0) { @@ -57,27 +57,10 @@ public class SplineInterpolator>( val a = points.y[j] val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 val d = (cOld - c) / (3.0 * h[j]) - val x0 = points.x[j] - val x02 = x0 * x0 - val x03 = x02 * x0 - //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = Polynomial( - a - b * x0 + c * x02 - d * x03, - b - 2 * c * x0 + 3 * d * x02, - c - 3 * d * x0, - d - ) + val polynomial = Polynomial(a, b, c, d) cOld = c - putLeft(x0, polynomial) + putLeft(points.x[j], polynomial) } } } } - - -public fun > Field.splineInterpolator( - bufferFactory: MutableBufferFactory, -): SplineInterpolator = SplineInterpolator(this, bufferFactory) - -public val DoubleField.splineInterpolator: SplineInterpolator - get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt deleted file mode 100644 index 3051cdd8d..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("LocalVariableName") - -package space.kscience.kmath.functions - -import space.kscience.kmath.functions.testUtils.* -import kotlin.test.* - - -class PolynomialTest { - @Test - fun test_Polynomial_Constant_plus() { - RationalField.polynomialSpace { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), - "test 2" - ) - assertEquals( - Polynomial(Rational(0)), - Polynomial(Rational(-2)) + Rational(2), - "test 3" - ) - assertEquals( - Polynomial(Rational(0)), - Polynomial() + Rational(0), - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - Polynomial(Rational(-2)) + Rational(1), - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - Polynomial() + Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_minus() { - RationalField.polynomialSpace { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), - "test 2" - ) - assertEquals( - Polynomial(Rational(0)), - Polynomial(Rational(2)) - Rational(2), - "test 3" - ) - assertEquals( - Polynomial(Rational(0)), - Polynomial() - Rational(0), - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - Polynomial(Rational(2)) - Rational(1), - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - Polynomial() - Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_times() { - IntModuloRing(35).polynomialSpace { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - Polynomial(22, 26, 13, 15, 26) * m(27), - "test 1" - ) - assertEquals( - Polynomial(0, 0, 0, 0, 0), - Polynomial(7, 0, 49, 21, 14) * m(15), - "test 2" - ) - } - } - @Test - fun test_Constant_Polynomial_plus() { - RationalField.polynomialSpace { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(-3) + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(2) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(Rational(0)), - Rational(2) + Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(Rational(0)), - Rational(0) + Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Rational(1) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - Rational(1) + Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - Rational(2) + Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_minus() { - RationalField.polynomialSpace { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(3) - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(-2) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(Rational(0)), - Rational(-2) - Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(Rational(0)), - Rational(0) - Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Rational(-1) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - Rational(-1) - Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - Rational(-2) - Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_times() { - IntModuloRing(35).polynomialSpace { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - m(27) * Polynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - Polynomial(0, 0, 0, 0, 0), - m(15) * Polynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_unaryMinus() { - RationalField.polynomialSpace { - assertEquals( - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), - -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Polynomial_plus() { - RationalField.polynomialSpace { - // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 - assertEquals( - Polynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + - Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), - "test 1" - ) - // (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2 - assertEquals( - Polynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), - Polynomial(Rational(-2, 9), Rational(-8, 3)) + - Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)), - "test 2" - ) - // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 - assertEquals( - Polynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), - Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + - Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), - "test 3" - ) - // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + - Polynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_minus() { - RationalField.polynomialSpace { - // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 - assertEquals( - Polynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - - Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), - "test 1" - ) - // (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2 - assertEquals( - Polynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), - Polynomial(Rational(-2, 9), Rational(-8, 3)) - - Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)), - "test 2" - ) - // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 - assertEquals( - Polynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), - Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - - Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), - "test 3" - ) - // (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0 - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - - Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).polynomialSpace { - // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 - assertEquals( - Polynomial(1, 0, 1, 0, 1), - Polynomial(1, -1, 1) * Polynomial(1, 1, 1), - "test 1" - ) - // Spoiler: 5 * 7 = 0 - assertEquals( - Polynomial(0, 0, 0, 0, 0), - Polynomial(5, -25, 10) * Polynomial(21, 14, -7), - "test 2" - ) - } - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt deleted file mode 100644 index 48e641335..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.functions.testUtils.Rational -import space.kscience.kmath.functions.testUtils.RationalField -import kotlin.test.Test -import kotlin.test.assertEquals - - -@OptIn(UnstableKMathAPI::class) -class PolynomialUtilTest { - @Test - fun test_Polynomial_value_Double() { - assertEquals( - 0.0, - Polynomial(1.0, -2.0, 1.0).value(1.0), - 0.001, - "test 1" - ) - assertEquals( - 0.0, - Polynomial(1.0, -2.0, 1.0).value(1.0), - 0.001, - "test 1" - ) - assertEquals( - 1.1931904761904761, - Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).value(0.2), - 0.001, - "test 2" - ) - assertEquals( - 0.5681904761904762, - Polynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).value(0.2), - 0.001, - "test 3" - ) - assertEquals( - 1.1811904761904761, - Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).value(0.2), - 0.001, - "test 4" - ) - assertEquals( - 1.1703333333333332, - Polynomial(0.625, 2.6666666666666665, 0.0, 1.5).value(0.2), - 0.001, - "test 5" - ) - } - @Test - fun test_Polynomial_value_Constant() { - assertEquals( - Rational(0), - Polynomial(Rational(1), Rational(-2), Rational(1)).value(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(25057, 21000), - Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .value(RationalField, Rational(1, 5)), - "test 2" - ) - assertEquals( - Rational(2983, 5250), - Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .value(RationalField, Rational(1, 5)), - "test 3" - ) - assertEquals( - Rational(4961, 4200), - Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) - .value(RationalField, Rational(1, 5)), - "test 4" - ) - assertEquals( - Rational(3511, 3000), - Polynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) - .value(RationalField, Rational(1, 5)), - "test 5" - ) - } - @Test - fun test_Polynomial_differentiate() { - assertEquals( - Polynomial(Rational(-2), Rational(2)), - Polynomial(Rational(1), Rational(-2), Rational(1)).differentiate(RationalField), - "test 1" - ) - assertEquals( - Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(RationalField), - "test 2" - ) - assertEquals( - Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(RationalField), - "test 3" - ) - assertEquals( - Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).differentiate(RationalField), - "test 4" - ) - } - @Test - fun test_Polynomial_integrate() { - assertEquals( - Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - Polynomial(Rational(1), Rational(-2), Rational(1)).integrate(RationalField), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(RationalField), - "test 2" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(RationalField), - "test 3" - ) - assertEquals( - Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).integrate(RationalField), - "test 4" - ) - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt deleted file mode 100644 index 3b7409e82..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") - -package space.kscience.kmath.functions.testUtils - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations - - -class IntModulo { - val residue: Int - val modulus: Int - - @PublishedApi - internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { - if (toCheckInput) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - this.residue = residue.mod(this.modulus) - } else { - this.residue = residue - this.modulus = modulus - } - } - - constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - - operator fun unaryPlus(): IntModulo = this - operator fun unaryMinus(): IntModulo = - IntModulo( - if (residue == 0) 0 else modulus - residue, - modulus, - toCheckInput = false - ) - operator fun plus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not add two residue different modulo" } - return IntModulo( - (residue + other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun plus(other: Int): IntModulo = - IntModulo( - (residue + other) % modulus, - modulus, - toCheckInput = false - ) - operator fun minus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not subtract two residue different modulo" } - return IntModulo( - (residue - other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun minus(other: Int): IntModulo = - IntModulo( - (residue - other) % modulus, - modulus, - toCheckInput = false - ) - operator fun times(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not multiply two residue different modulo" } - return IntModulo( - (residue * other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun times(other: Int): IntModulo = - IntModulo( - (residue * other) % modulus, - modulus, - toCheckInput = false - ) - operator fun div(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not divide two residue different modulo" } - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun div(other: Int): IntModulo { - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - override fun equals(other: Any?): Boolean = - when (other) { - is IntModulo -> residue == other.residue && modulus == other.modulus - else -> false - } - - override fun hashCode(): Int = residue.hashCode() - - override fun toString(): String = "$residue mod $modulus" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -class IntModuloRing : Ring, ScaleOperations { - - val modulus: Int - - constructor(modulus: Int) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - } - - override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) - override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - - fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) - - override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right - override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right - - override inline fun IntModulo.unaryMinus(): IntModulo = -this - override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg - override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg - override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg - - override fun scale(a: IntModulo, value: Double): IntModulo = a * value.toInt() -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt deleted file mode 100644 index ffab2157c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions.testUtils - -import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.functions.PolynomialSpace - - -fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = - Polynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = - Polynomial(coefs.map { IntModulo(it, modulus) }) - -fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -fun PolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt deleted file mode 100644 index ff05805da..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") - -package space.kscience.kmath.functions.testUtils - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.NumbersAddOps - -@Suppress("NAME_SHADOWING") -class Rational { - companion object { - val ZERO: Rational = Rational(0L) - val ONE: Rational = Rational(1L) - } - - val numerator: Long - val denominator: Long - - internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { - if (toCheckInput) { - if (denominator == 0L) throw ArithmeticException("/ by zero") - - val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } - - this.numerator = numerator / greatestCommonDivider - this.denominator = denominator / greatestCommonDivider - } else { - this.numerator = numerator - this.denominator = denominator - } - } - - constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) - constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) - constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) - constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) - constructor(numerator: Int) : this(numerator.toLong(), 1L, false) - constructor(numerator: Long) : this(numerator, 1L, false) - - operator fun unaryPlus(): Rational = this - operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - operator fun plus(other: Rational): Rational { - val denominatorsGcd = gcd(denominator, other.denominator) - val dividedThisDenominator = denominator / denominatorsGcd - val dividedOtherDenominator = other.denominator / denominatorsGcd - val numeratorCandidate = numerator * dividedOtherDenominator + dividedThisDenominator * other.numerator - val secondGcd = gcd(numeratorCandidate, denominatorsGcd) - return Rational( - numeratorCandidate / secondGcd, - dividedThisDenominator * (other.denominator / secondGcd), - toCheckInput = false - ) - } - operator fun plus(other: Int): Rational = - Rational( - numerator + denominator * other.toLong(), - denominator, - toCheckInput = false - ) - operator fun plus(other: Long): Rational = - Rational( - numerator + denominator * other, - denominator, - toCheckInput = false - ) - operator fun minus(other: Rational): Rational { - val denominatorsGcd = gcd(denominator, other.denominator) - val dividedThisDenominator = denominator / denominatorsGcd - val dividedOtherDenominator = other.denominator / denominatorsGcd - val numeratorCandidate = numerator * dividedOtherDenominator - dividedThisDenominator * other.numerator - val secondGcd = gcd(numeratorCandidate, denominatorsGcd) - return Rational( - numeratorCandidate / secondGcd, - dividedThisDenominator * (other.denominator / secondGcd), - toCheckInput = false - ) - } - operator fun minus(other: Int): Rational = - Rational( - numerator - denominator * other.toLong(), - denominator, - toCheckInput = false - ) - operator fun minus(other: Long): Rational = - Rational( - numerator - denominator * other, - denominator, - toCheckInput = false - ) - operator fun times(other: Rational): Rational { - val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) - val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) - return Rational( - (numerator / otherDenominatorAndThisNumeratorGcd) * (other.numerator / thisDenominatorAndOtherNumeratorGcd), - (denominator / thisDenominatorAndOtherNumeratorGcd) * (other.denominator / otherDenominatorAndThisNumeratorGcd), - toCheckInput = false - ) - } - operator fun times(other: Int): Rational { - val other = other.toLong() - val denominatorAndOtherGcd = gcd(denominator, other) - return Rational( - numerator * (other / denominatorAndOtherGcd), - denominator / denominatorAndOtherGcd, - toCheckInput = false - ) - } - operator fun times(other: Long): Rational { - val denominatorAndOtherGcd = gcd(denominator, other) - return Rational( - numerator * (other / denominatorAndOtherGcd), - denominator / denominatorAndOtherGcd, - toCheckInput = false - ) - } - operator fun div(other: Rational): Rational { - val denominatorsGcd = gcd(denominator, other.denominator) - val numeratorsGcd = gcd(numerator, other.numerator) - return Rational( - (numerator / numeratorsGcd) * (other.denominator / denominatorsGcd), - (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) - ) - } - operator fun div(other: Int): Rational { - val other = other.toLong() - val numeratorAndOtherGcd = gcd(numerator, other) - return Rational( - numerator / numeratorAndOtherGcd, - denominator * (other / numeratorAndOtherGcd), - toCheckInput = false - ) - } - operator fun div(other: Long): Rational { - val numeratorAndOtherGcd = gcd(numerator, other) - return Rational( - numerator / numeratorAndOtherGcd, - denominator * (other / numeratorAndOtherGcd), - toCheckInput = false - ) - } - override fun equals(other: Any?): Boolean = - when (other) { - is Rational -> numerator == other.numerator && denominator == other.denominator - is Int -> numerator == other && denominator == 1L - is Long -> numerator == other && denominator == 1L - else -> false - } - - override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() - - override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -@OptIn(UnstableKMathAPI::class) -object RationalField : Field, NumbersAddOps { - override inline val zero: Rational get() = Rational.ZERO - override inline val one: Rational get() = Rational.ONE - - override inline fun number(value: Number): Rational = Rational(value.toLong()) - - override inline fun add(left: Rational, right: Rational): Rational = left + right - override inline fun multiply(left: Rational, right: Rational): Rational = left * right - override inline fun divide(left: Rational, right: Rational): Rational = left / right - override inline fun scale(a: Rational, value: Double): Rational = a * number(value) - - override inline fun Rational.unaryMinus(): Rational = -this - override inline fun Rational.plus(arg: Rational): Rational = this + arg - override inline fun Rational.minus(arg: Rational): Rational = this - arg - override inline fun Rational.times(arg: Rational): Rational = this * arg - override inline fun Rational.div(arg: Rational): Rational = this / arg -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt deleted file mode 100644 index 61b50f128..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions.testUtils - -import kotlin.math.abs - - -internal data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) - -internal tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) - -internal fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = - when { - a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } - a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } - b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } - else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) - } - -internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = - if (b == 0) BezoutIdentityWithGCD(m1, m3, a) - else { - val quotient = a / b - val reminder = a % b - bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) - } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt index 7424f3566..5ec90f42a 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt @@ -1,11 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.integration -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import kotlin.math.PI import kotlin.math.sin @@ -16,22 +16,22 @@ import kotlin.test.assertEquals class GaussIntegralTest { @Test fun gaussSin() { - val res = DoubleField.gaussIntegrator.integrate(0.0..2 * PI) { x -> + val res = DoubleField.integrate(0.0..2 * PI) { x -> sin(x) } - assertEquals(0.0, res.value, 1e-2) + assertEquals(0.0, res.value!!, 1e-4) } @Test fun gaussUniform() { - val res = DoubleField.gaussIntegrator.integrate(35.0..100.0) { x -> + val res = DoubleField.integrate(0.0..100.0,300) { x -> if(x in 30.0..50.0){ 1.0 } else { 0.0 } } - assertEquals(15.0, res.value, 0.5) + assertEquals(20.0, res.value!!, 0.5) } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt deleted file mode 100644 index 7b699ebbc..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class SimpsonIntegralTest { - @Test - fun gaussSin() { - val res = DoubleField.simpsonIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> - sin(x) - } - assertEquals(0.0, res.value, 1e-2) - } - - @Test - fun gaussUniform() { - val res = DoubleField.simpsonIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> - if (x in 30.0..50.0) { - 1.0 - } else { - 0.0 - } - } - assertEquals(15.0, res.value, 0.5) - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt deleted file mode 100644 index b17d21abf..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class SplineIntegralTest { - - @Test - fun integratePolynomial(){ - val polynomial = Polynomial(1.0, 2.0, 3.0) - val integral = polynomial.integrate(DoubleField,1.0..2.0) - assertEquals(11.0, integral, 0.001) - } - - @Test - fun gaussSin() { - val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> - sin(x) - } - assertEquals(0.0, res.value, 1e-2) - } - - @Test - fun gaussUniform() { - val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> - if(x in 30.0..50.0){ - 1.0 - } else { - 0.0 - } - } - assertEquals(15.0, res.value, 0.5) - } - - -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt index c0ca6c484..bec678bae 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt @@ -1,10 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.interpolation +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.asFunction import space.kscience.kmath.operations.DoubleField import kotlin.test.Test import kotlin.test.assertEquals @@ -19,8 +21,8 @@ internal class LinearInterpolatorTest { 3.0 to 4.0 ) - //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) - val function = DoubleField.linearInterpolator.interpolate(data) + val polynomial: PiecewisePolynomial = LinearInterpolator(DoubleField).interpolatePolynomials(data) + val function = polynomial.asFunction(DoubleField) assertEquals(null, function(-1.0)) assertEquals(0.5, function(0.5)) assertEquals(2.0, function(1.5)) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt deleted file mode 100644 index 851a8ab7d..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class SplineInterpolatorTest { - @Test - fun testInterpolation() { - val data = (0..10).map { - val x = it.toDouble() / 5 * PI - x to sin(x) - } - - //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) - - val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) - - assertEquals(Double.NaN, function(-1.0)) - assertEquals(sin(0.5), function(0.5), 0.1) - assertEquals(sin(1.5), function(1.5), 0.1) - assertEquals(sin(2.0), function(2.0), 0.1) - } -} diff --git a/kmath-geometry/README.md b/kmath-geometry/README.md deleted file mode 100644 index 480945c4f..000000000 --- a/kmath-geometry/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-geometry - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-geometry:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-geometry:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-geometry:0.4.0-dev-1") -} -``` diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index 32926db7e..65db43edf 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -1,24 +1,21 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity + plugins { - id("space.kscience.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") } -kscience{ - jvm() - js() - native() - - useContextReceivers() - useSerialization() - dependencies{ - api(projects.kmath.kmathComplex) +kotlin.sourceSets.commonMain { + dependencies { + api(project(":kmath-core")) } - - testDependencies { - implementation(projects.testUtils) - } - } readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE + maturity = Maturity.PROTOTYPE } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt deleted file mode 100644 index d37ed45c0..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import kotlinx.serialization.Serializable -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import kotlin.math.* - -/** - * A circle in 2D space - */ -@Serializable -public data class Circle2D( - @Serializable(Euclidean2DSpace.VectorSerializer::class) public val center: DoubleVector2D, - public val radius: Double -) - - -public val Circle2D.circumference: Double get() = radius * 2 * PI diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt index 3df8dba7b..3604fda31 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt @@ -1,90 +1,55 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.geometry -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder import space.kscience.kmath.linear.Point -import space.kscience.kmath.operations.Norm +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.GroupElement import space.kscience.kmath.operations.ScaleOperations -import kotlin.math.pow +import space.kscience.kmath.operations.invoke import kotlin.math.sqrt -public interface Vector2D : Point, Vector { - public val x: T - public val y: T - override val size: Int get() = 2 +@OptIn(UnstableKMathAPI::class) +public interface Vector2D : Point, Vector, GroupElement { + public val x: Double + public val y: Double + public override val context: Euclidean2DSpace get() = Euclidean2DSpace + public override val size: Int get() = 2 - override operator fun get(index: Int): T = when (index) { - 0 -> x - 1 -> y + public override operator fun get(index: Int): Double = when (index) { + 1 -> x + 2 -> y else -> error("Accessing outside of point bounds") } - override operator fun iterator(): Iterator = iterator { - yield(x) - yield(y) - } + public override operator fun iterator(): Iterator = listOf(x, y).iterator() } +public val Vector2D.r: Double + get() = Euclidean2DSpace { sqrt(norm()) } -public operator fun Vector2D.component1(): T = x -public operator fun Vector2D.component2(): T = y - -public typealias DoubleVector2D = Vector2D -public typealias Float64Vector2D = Vector2D - -public val Vector2D.r: Double get() = Euclidean2DSpace.norm(this) +@Suppress("FunctionName") +public fun Vector2D(x: Double, y: Double): Vector2D = Vector2DImpl(x, y) +private data class Vector2DImpl( + override val x: Double, + override val y: Double, +) : Vector2D /** * 2D Euclidean space */ -public object Euclidean2DSpace : GeometrySpace, - ScaleOperations, - Norm { +public object Euclidean2DSpace : GeometrySpace, ScaleOperations { + public override val zero: Vector2D by lazy { Vector2D(0.0, 0.0) } - @Serializable - @SerialName("Float64Vector2D") - private data class Vector2DImpl( - override val x: Double, - override val y: Double, - ) : DoubleVector2D + public fun Vector2D.norm(): Double = sqrt(x * x + y * y) + override fun Vector2D.unaryMinus(): Vector2D = Vector2D(-x, -y) - public object VectorSerializer : KSerializer { - private val proxySerializer = Vector2DImpl.serializer() - override val descriptor: SerialDescriptor get() = proxySerializer.descriptor - - override fun deserialize(decoder: Decoder): DoubleVector2D = decoder.decodeSerializableValue(proxySerializer) - - override fun serialize(encoder: Encoder, value: DoubleVector2D) { - val vector = value as? Vector2DImpl ?: Vector2DImpl(value.x, value.y) - encoder.encodeSerializableValue(proxySerializer, vector) - } - } - - public fun vector(x: Number, y: Number): DoubleVector2D = Vector2DImpl(x.toDouble(), y.toDouble()) - - override val zero: DoubleVector2D by lazy { vector(0.0, 0.0) } - - override fun norm(arg: DoubleVector2D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2)) - - override fun DoubleVector2D.unaryMinus(): DoubleVector2D = vector(-x, -y) - - override fun DoubleVector2D.distanceTo(other: DoubleVector2D): Double = norm(this - other) - override fun add(left: DoubleVector2D, right: DoubleVector2D): DoubleVector2D = - vector(left.x + right.x, left.y + right.y) - - override fun scale(a: DoubleVector2D, value: Double): DoubleVector2D = vector(a.x * value, a.y * value) - override fun DoubleVector2D.dot(other: DoubleVector2D): Double = x * other.x + y * other.y - - public val xAxis: DoubleVector2D = vector(1.0, 0.0) - public val yAxis: DoubleVector2D = vector(0.0, 1.0) + public override fun Vector2D.distanceTo(other: Vector2D): Double = (this - other).norm() + public override fun add(a: Vector2D, b: Vector2D): Vector2D = Vector2D(a.x + b.x, a.y + b.y) + public override fun scale(a: Vector2D, value: Double): Vector2D = Vector2D(a.x * value, a.y * value) + public override fun Vector2D.dot(other: Vector2D): Double = x * other.x + y * other.y } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt index 3059cefe6..8643b2dbb 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt @@ -1,149 +1,60 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.geometry -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder import space.kscience.kmath.linear.Point -import space.kscience.kmath.operations.Norm +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.GroupElement import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.structures.Buffer -import kotlin.math.pow +import space.kscience.kmath.operations.invoke import kotlin.math.sqrt -public interface Vector3D : Point, Vector { - public val x: T - public val y: T - public val z: T - override val size: Int get() = 3 +@OptIn(UnstableKMathAPI::class) +public interface Vector3D : Point, Vector, GroupElement { + public val x: Double + public val y: Double + public val z: Double + public override val context: Euclidean3DSpace get() = Euclidean3DSpace + public override val size: Int get() = 3 - override operator fun get(index: Int): T = when (index) { - 0 -> x - 1 -> y - 2 -> z + public override operator fun get(index: Int): Double = when (index) { + 1 -> x + 2 -> y + 3 -> z else -> error("Accessing outside of point bounds") } - override operator fun iterator(): Iterator = listOf(x, y, z).iterator() + public override operator fun iterator(): Iterator = listOf(x, y, z).iterator() } -public operator fun Vector3D.component1(): T = x -public operator fun Vector3D.component2(): T = y -public operator fun Vector3D.component3(): T = z +@Suppress("FunctionName") +public fun Vector3D(x: Double, y: Double, z: Double): Vector3D = Vector3DImpl(x, y, z) -public fun Buffer.asVector3D(): Vector3D = object : Vector3D { - init { - require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" } - } +public val Vector3D.r: Double get() = Euclidean3DSpace { sqrt(norm()) } - override val x: T get() = this@asVector3D[0] - override val y: T get() = this@asVector3D[1] - override val z: T get() = this@asVector3D[2] +private data class Vector3DImpl( + override val x: Double, + override val y: Double, + override val z: Double, +) : Vector3D - override fun toString(): String = this@asVector3D.toString() -} +public object Euclidean3DSpace : GeometrySpace, ScaleOperations { + public override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) } -public typealias DoubleVector3D = Vector3D -public typealias Float64Vector3D = Vector3D + public fun Vector3D.norm(): Double = sqrt(x * x + y * y + z * z) + override fun Vector3D.unaryMinus(): Vector3D = Vector3D(-x, -y, -z) -public val DoubleVector3D.r: Double get() = Euclidean3DSpace.norm(this) + public override fun Vector3D.distanceTo(other: Vector3D): Double = (this - other).norm() -public object Euclidean3DSpace : GeometrySpace, ScaleOperations, - Norm { + public override fun add(a: Vector3D, b: Vector3D): Vector3D = + Vector3D(a.x + b.x, a.y + b.y, a.z + b.z) - @Serializable - @SerialName("Float64Vector3D") - private data class Vector3DImpl( - override val x: Double, - override val y: Double, - override val z: Double, - ) : DoubleVector3D + public override fun scale(a: Vector3D, value: Double): Vector3D = + Vector3D(a.x * value, a.y * value, a.z * value) - public object VectorSerializer : KSerializer { - private val proxySerializer = Vector3DImpl.serializer() - override val descriptor: SerialDescriptor get() = proxySerializer.descriptor - - override fun deserialize(decoder: Decoder): DoubleVector3D = decoder.decodeSerializableValue(proxySerializer) - - override fun serialize(encoder: Encoder, value: DoubleVector3D) { - val vector = value as? Vector3DImpl ?: Vector3DImpl(value.x, value.y, value.z) - encoder.encodeSerializableValue(proxySerializer, vector) - } - } - - public fun vector(x: Double, y: Double, z: Double): DoubleVector3D = - Vector3DImpl(x, y, z) - - public fun vector(x: Number, y: Number, z: Number): DoubleVector3D = - vector(x.toDouble(), y.toDouble(), z.toDouble()) - - override val zero: DoubleVector3D by lazy { vector(0.0, 0.0, 0.0) } - - override fun norm(arg: DoubleVector3D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2) + arg.z.pow(2)) - - public fun DoubleVector3D.norm(): Double = norm(this) - - override fun DoubleVector3D.unaryMinus(): DoubleVector3D = vector(-x, -y, -z) - - override fun DoubleVector3D.distanceTo(other: DoubleVector3D): Double = (this - other).norm() - - override fun add(left: DoubleVector3D, right: DoubleVector3D): DoubleVector3D = - vector(left.x + right.x, left.y + right.y, left.z + right.z) - - override fun scale(a: DoubleVector3D, value: Double): DoubleVector3D = - vector(a.x * value, a.y * value, a.z * value) - - override fun DoubleVector3D.dot(other: DoubleVector3D): Double = + public override fun Vector3D.dot(other: Vector3D): Double = x * other.x + y * other.y + z * other.z - - private fun leviCivita(i: Int, j: Int, k: Int): Int = when { - // even permutation - i == 0 && j == 1 && k == 2 -> 1 - i == 1 && j == 2 && k == 0 -> 1 - i == 2 && j == 0 && k == 1 -> 1 - // odd permutations - i == 2 && j == 1 && k == 0 -> -1 - i == 0 && j == 2 && k == 1 -> -1 - i == 1 && j == 0 && k == 2 -> -1 - - else -> 0 - } - - /** - * Compute vector product of [first] and [second]. The basis assumed to be right-handed. - */ - public fun vectorProduct( - first: DoubleVector3D, - second: DoubleVector3D, - ): DoubleVector3D { - var x = 0.0 - var y = 0.0 - var z = 0.0 - - for (j in (0..2)) { - for (k in (0..2)) { - x += leviCivita(0, j, k) * first[j] * second[k] - y += leviCivita(1, j, k) * first[j] * second[k] - z += leviCivita(2, j, k) * first[j] * second[k] - } - } - - return vector(x, y, z) - } - - /** - * Vector product with right basis - */ - public infix fun DoubleVector3D.cross(other: DoubleVector3D): Vector3D = vectorProduct(this, other) - - public val xAxis: DoubleVector3D = vector(1.0, 0.0, 0.0) - public val yAxis: DoubleVector3D = vector(0.0, 1.0, 0.0) - public val zAxis: DoubleVector3D = vector(0.0, 0.0, 1.0) } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt index d6d7e5725..d4245c744 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt @@ -1,17 +1,16 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.geometry import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.ScaleOperations public interface Vector -public interface GeometrySpace : Group, ScaleOperations, Norm { +public interface GeometrySpace : Group, ScaleOperations { /** * L2 distance */ @@ -21,11 +20,4 @@ public interface GeometrySpace : Group, ScaleOperations, Norm< * Scalar product */ public infix fun V.dot(other: V): Double - - public companion object{ - /** - * Default precision for geometry objects comparison - */ - internal const val DEFAULT_PRECISION = 1e-6 - } } \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt index a7f6ae35d..5a6d23709 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt @@ -1,51 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.geometry -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +public data class Line(val base: V, val direction: V) -/** - * A line formed by [start] vector of start and a [direction] vector. Direction vector is not necessarily normalized, - * but its length does not affect line properties - */ -public interface Line { - public val start: V - public val direction: V -} - -@Serializable -@SerialName("Line") -private data class LineImpl(override val start: V, override val direction: V): Line - -public fun Line(base: V, direction: V): Line = LineImpl(base, direction) - -public typealias Line2D = Line -public typealias Line3D = Line - -/** - * A directed line segment between [begin] and [end] - */ -public interface LineSegment { - public val begin: V - public val end: V -} - -/** - * Basic implementation for [LineSegment] - */ -@Serializable -@SerialName("LineSegment") -private data class LineSegmentImpl(override val begin: V, override val end: V) : LineSegment - -public fun LineSegment(begin: V, end: V): LineSegment = LineSegmentImpl(begin, end) - -public fun LineSegment.line(algebra: GeometrySpace): Line = with(algebra) { - Line(begin, end - begin) -} - -public typealias LineSegment2D = LineSegment -public typealias LineSegment3D = LineSegment +public typealias Line2D = Line +public typealias Line3D = Line diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt deleted file mode 100644 index 20f4a031e..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - - -/** - * A closed polygon in 2D space - */ -public interface Polygon { - public val points: List> -} \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt index 21045e94e..a7a28b596 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt deleted file mode 100644 index 3855514fb..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlin.jvm.JvmInline -import kotlin.math.PI -import kotlin.math.floor - -@Serializable(AngleSerializer::class) -public sealed interface Angle : Comparable { - public fun toRadians(): Radians - public fun toDegrees(): Degrees - - public operator fun plus(other: Angle): Angle - public operator fun minus(other: Angle): Angle - - public operator fun times(other: Number): Angle - public operator fun div(other: Number): Angle - public operator fun div(other: Angle): Double - public operator fun unaryMinus(): Angle - - public companion object { - public val zero: Radians = Radians(0.0) - public val pi: Radians = Radians(PI) - public val piTimes2: Radians = Radians(PI * 2) - public val piDiv2: Radians = Radians(PI / 2) - } -} - - -public object AngleSerializer : KSerializer { - override val descriptor: SerialDescriptor get() = Double.serializer().descriptor - - override fun deserialize(decoder: Decoder): Angle = decoder.decodeDouble().degrees - - override fun serialize(encoder: Encoder, value: Angle) { - encoder.encodeDouble(value.degrees) - } -} - -/** - * Type safe radians - */ -@Serializable -@JvmInline -public value class Radians(public val value: Double) : Angle { - override fun toRadians(): Radians = this - override fun toDegrees(): Degrees = Degrees(value * 180 / PI) - - public override fun plus(other: Angle): Radians = Radians(value + other.radians) - public override fun minus(other: Angle): Radians = Radians(value - other.radians) - - public override fun times(other: Number): Radians = Radians(value * other.toDouble()) - public override fun div(other: Number): Radians = Radians(value / other.toDouble()) - override fun div(other: Angle): Double = value / other.radians - - public override fun unaryMinus(): Radians = Radians(-value) - - override fun compareTo(other: Angle): Int = value.compareTo(other.radians) -} - -public fun sin(angle: Angle): Double = kotlin.math.sin(angle.toRadians().value) -public fun cos(angle: Angle): Double = kotlin.math.cos(angle.toRadians().value) -public fun tan(angle: Angle): Double = kotlin.math.tan(angle.toRadians().value) - -public val Number.radians: Radians get() = Radians(toDouble()) - -public val Angle.radians: Double get() = toRadians().value - -/** - * Type safe degrees - */ -@JvmInline -public value class Degrees(public val value: Double) : Angle { - override fun toRadians(): Radians = Radians(value * PI / 180) - override fun toDegrees(): Degrees = this - - public override fun plus(other: Angle): Degrees = Degrees(value + other.degrees) - public override fun minus(other: Angle): Degrees = Degrees(value - other.degrees) - - public override fun times(other: Number): Degrees = Degrees(value * other.toDouble()) - public override fun div(other: Number): Degrees = Degrees(value / other.toDouble()) - override fun div(other: Angle): Double = value / other.degrees - - public override fun unaryMinus(): Degrees = Degrees(-value) - - override fun compareTo(other: Angle): Int = value.compareTo(other.degrees) -} - -public val Number.degrees: Degrees get() = Degrees(toDouble()) - -public val Angle.degrees: Double get() = toDegrees().value - -/** - * Normalized angle 2 PI range symmetric around [center]. By default, uses (0, 2PI) range. - */ -public fun Angle.normalized(center: Angle = Angle.pi): Angle = - this - Angle.piTimes2 * floor((radians + PI - center.radians) / PI / 2) - -public fun abs(angle: Angle): Angle = if (angle < Angle.zero) -angle else angle \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt deleted file mode 100644 index ea46ab90f..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import space.kscience.kmath.geometry.GeometrySpace.Companion.DEFAULT_PRECISION - -/** - * Float equality within given [precision] - */ -public fun Double.equalsFloat(other: Double, precision: Double = DEFAULT_PRECISION): Boolean = - kotlin.math.abs(this - other) < precision - -/** - * Float equality within given [precision] - */ -public fun Double.equalsFloat(other: Float, precision: Double = DEFAULT_PRECISION): Boolean = - kotlin.math.abs(this - other) < precision - -/** - * Vector equality within given [precision] (using [GeometrySpace.norm] provided by the space - */ -public fun V.equalsVector( - space: GeometrySpace, - other: V, - precision: Double = DEFAULT_PRECISION, -): Boolean = with(space) { - norm(this@equalsVector - other) < precision -} - -/** - * Vector equality using Euclidian L2 norm and given [precision] - */ -public fun Float64Vector2D.equalsVector( - other: Float64Vector2D, - precision: Double = DEFAULT_PRECISION, -): Boolean = equalsVector(Euclidean2DSpace, other, precision) - -/** - * Vector equality using Euclidian L2 norm and given [precision] - */ -public fun Float64Vector3D.equalsVector( - other: Float64Vector3D, - precision: Double = DEFAULT_PRECISION, -): Boolean = equalsVector(Euclidean3DSpace, other, precision) - -/** - * Line equality using [GeometrySpace.norm] provided by the [space] and given [precision] - */ -public fun LineSegment.equalsLine( - space: GeometrySpace, - other: LineSegment, - precision: Double = DEFAULT_PRECISION, -): Boolean = begin.equalsVector(space, other.begin, precision) && end.equalsVector(space, other.end, precision) \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt deleted file mode 100644 index c5c3487a1..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -//TODO move vector to receiver - -/** - * Project vector onto a line. - * @param vector to project - * @param line line to which vector should be projected - */ -public fun GeometrySpace.projectToLine(vector: V, line: Line): V = with(line) { - start + (direction dot (vector - start)) / (direction dot direction) * direction -} - -/** - * Project vector onto a hyperplane, which is defined by a normal and base. - * In 2D case it is the projection to a line, in 3d case it is the one to a plane. - * @param vector to project - * @param normal normal (perpendicular) vector to a hyper-plane to which vector should be projected - * @param base point belonging to a hyper-plane to which vector should be projected - */ -public fun GeometrySpace.projectAlong(vector: V, normal: V, base: V): V = - vector + normal * ((base - vector) dot normal) / (normal dot normal) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt deleted file mode 100644 index 1f3850c7c..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.complex.Quaternion -import space.kscience.kmath.complex.QuaternionField -import space.kscience.kmath.complex.normalized -import space.kscience.kmath.complex.reciprocal -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.linear.matrix -import space.kscience.kmath.operations.DoubleField -import kotlin.math.pow -import kotlin.math.sqrt - -internal fun DoubleVector3D.toQuaternion(): Quaternion = Quaternion(0.0, x, y, z) - -/** - * Angle in radians denoted by this quaternion rotation - */ -public val Quaternion.theta: Radians get() = (kotlin.math.acos(normalized().w) * 2).radians - -/** - * Create a normalized Quaternion from rotation angle and rotation vector - */ -public fun Quaternion.Companion.fromRotation(theta: Angle, vector: DoubleVector3D): Quaternion { - val s = sin(theta / 2) - val c = cos(theta / 2) - val norm = with(Euclidean3DSpace) { vector.norm() } - return Quaternion(c, vector.x * s / norm, vector.y * s / norm, vector.z * s / norm) -} - -/** - * An axis of quaternion rotation - */ -public val Quaternion.vector: DoubleVector3D - get() { - return object : DoubleVector3D { - private val sint2 = sqrt(1 - w * w) - override val x: Double get() = this@vector.x / sint2 - override val y: Double get() = this@vector.y / sint2 - override val z: Double get() = this@vector.z / sint2 - override fun toString(): String = listOf(x, y, z).toString() - } - } - -/** - * Rotate a vector in a [Euclidean3DSpace] - */ -public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, q: Quaternion): DoubleVector3D = with(QuaternionField) { - val p = vector.toQuaternion() - (q * p * q.reciprocal).vector -} - -/** - * Use a composition of quaternions to create a rotation - */ -@UnstableKMathAPI -public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, composition: QuaternionField.() -> Quaternion): DoubleVector3D = - rotate(vector, QuaternionField.composition()) - -public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, matrix: Matrix): DoubleVector3D { - require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" } - return with(DoubleField.linearSpace) { matrix.dot(vector).asVector3D() } -} - -/** - * Convert a [Quaternion] to a rotation matrix - */ -@OptIn(UnstableKMathAPI::class) -public fun Quaternion.toRotationMatrix( - linearSpace: LinearSpace = DoubleField.linearSpace, -): Matrix { - val s = QuaternionField.norm(this).pow(-2) - return linearSpace.matrix(3, 3)( - 1.0 - 2 * s * (y * y + z * z), 2 * s * (x * y - z * w), 2 * s * (x * z + y * w), - 2 * s * (x * y + z * w), 1.0 - 2 * s * (x * x + z * z), 2 * s * (y * z - x * w), - 2 * s * (x * z - y * w), 2 * s * (y * z + x * w), 1.0 - 2 * s * (x * x + y * y) - ) -} - -/** - * taken from https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ - */ -public fun Quaternion.Companion.fromRotationMatrix(matrix: Matrix): Quaternion { - require(matrix.colNum == 3 && matrix.rowNum == 3) { "Rotation matrix should be 3x3 but is ${matrix.rowNum}x${matrix.colNum}" } - val trace = matrix[0, 0] + matrix[1, 1] + matrix[2, 2] - - return if (trace > 0) { - val s = sqrt(trace + 1.0) * 2 // S=4*qw - Quaternion( - w = 0.25 * s, - x = (matrix[2, 1] - matrix[1, 2]) / s, - y = (matrix[0, 2] - matrix[2, 0]) / s, - z = (matrix[1, 0] - matrix[0, 1]) / s, - ) - } else if ((matrix[0, 0] > matrix[1, 1]) && (matrix[0, 0] > matrix[2, 2])) { - val s = sqrt(1.0 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2]) * 2 // S=4*qx - Quaternion( - w = (matrix[2, 1] - matrix[1, 2]) / s, - x = 0.25 * s, - y = (matrix[0, 1] + matrix[1, 0]) / s, - z = (matrix[0, 2] + matrix[2, 0]) / s, - ) - } else if (matrix[1, 1] > matrix[2, 2]) { - val s = sqrt(1.0 + matrix[1, 1] - matrix[0, 0] - matrix[2, 2]) * 2 // S=4*qy - Quaternion( - w = (matrix[0, 2] - matrix[2, 0]) / s, - x = (matrix[0, 1] + matrix[1, 0]) / s, - y = 0.25 * s, - z = (matrix[1, 2] + matrix[2, 1]) / s, - ) - } else { - val s = sqrt(1.0 + matrix[2, 2] - matrix[0, 0] - matrix[1, 1]) * 2 // S=4*qz - Quaternion( - w = (matrix[1, 0] - matrix[0, 1]) / s, - x = (matrix[0, 2] + matrix[2, 0]) / s, - y = (matrix[1, 2] + matrix[2, 1]) / s, - z = 0.25 * s, - ) - } -} - -public enum class RotationOrder { - // proper Euler - XZX, - XYX, - YXY, - YZY, - ZYZ, - ZXZ, - - //Tait–Bryan - XZY, - XYZ, - YXZ, - YZX, - ZYX, - ZXY -} - -/** - * Based on https://github.com/mrdoob/three.js/blob/master/src/math/Quaternion.js - */ -public fun Quaternion.Companion.fromEuler( - a: Angle, - b: Angle, - c: Angle, - rotationOrder: RotationOrder, -): Quaternion { - val c1 = cos (a / 2) - val c2 = cos (b / 2) - val c3 = cos (c / 2) - - val s1 = sin (a / 2) - val s2 = sin (b / 2) - val s3 = sin (c / 2) - - return when (rotationOrder) { - - RotationOrder.XYZ -> Quaternion( - c1 * c2 * c3 - s1 * s2 * s3, - s1 * c2 * c3 + c1 * s2 * s3, - c1 * s2 * c3 - s1 * c2 * s3, - c1 * c2 * s3 + s1 * s2 * c3 - ) - - RotationOrder.YXZ -> Quaternion( - c1 * c2 * c3 + s1 * s2 * s3, - s1 * c2 * c3 + c1 * s2 * s3, - c1 * s2 * c3 - s1 * c2 * s3, - c1 * c2 * s3 - s1 * s2 * c3 - ) - - RotationOrder.ZXY -> Quaternion( - c1 * c2 * c3 - s1 * s2 * s3, - s1 * c2 * c3 - c1 * s2 * s3, - c1 * s2 * c3 + s1 * c2 * s3, - c1 * c2 * s3 + s1 * s2 * c3 - ) - - - RotationOrder.ZYX -> Quaternion( - c1 * c2 * c3 + s1 * s2 * s3, - s1 * c2 * c3 - c1 * s2 * s3, - c1 * s2 * c3 + s1 * c2 * s3, - c1 * c2 * s3 - s1 * s2 * c3 - ) - - RotationOrder.YZX -> Quaternion( - c1 * c2 * c3 - s1 * s2 * s3, - s1 * c2 * c3 + c1 * s2 * s3, - c1 * s2 * c3 + s1 * c2 * s3, - c1 * c2 * s3 - s1 * s2 * c3 - ) - - RotationOrder.XZY -> Quaternion( - c1 * c2 * c3 + s1 * s2 * s3, - s1 * c2 * c3 - c1 * s2 * s3, - c1 * s2 * c3 - s1 * c2 * s3, - c1 * c2 * s3 + s1 * s2 * c3 - ) - else -> TODO("Proper Euler rotation orders are not supported yet") - } -} \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt deleted file mode 100644 index b8086eb75..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package space.kscience.kmath.geometry - -import kotlin.test.Test -import kotlin.test.assertEquals - -class AngleTest { - @Test - fun normalization() { - assertEquals(30.degrees, 390.degrees.normalized()) - assertEquals(30.degrees, (-330).degrees.normalized()) - assertEquals(200.degrees, 200.degrees.normalized()) - assertEquals(30.degrees, 390.degrees.normalized(Angle.zero)) - assertEquals(30.degrees, (-330).degrees.normalized(Angle.zero)) - assertEquals((-160).degrees, 200.degrees.normalized(Angle.zero)) - } -} \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt deleted file mode 100644 index 22cbee6f0..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import kotlin.math.sqrt -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class Euclidean2DSpaceTest { - @Test - fun zero() { - assertVectorEquals(Euclidean2DSpace.vector(0.0, 0.0), Euclidean2DSpace.zero) - } - - @Test - fun norm() { - with(Euclidean2DSpace) { - assertEquals(0.0, norm(zero)) - assertEquals(1.0, norm(vector(1.0, 0.0))) - assertEquals(sqrt(2.0), norm(vector(1.0, 1.0))) - assertEquals(sqrt(5.002001), norm(vector(-2.0, 1.001))) - } - } - - @Test - fun dotProduct() { - with(Euclidean2DSpace) { - assertEquals(0.0, zero dot zero) - assertEquals(0.0, zero dot vector(1.0, 0.0)) - assertEquals(0.0, vector(-2.0, 0.001) dot zero) - assertEquals(0.0, vector(1.0, 0.0) dot vector(0.0, 1.0)) - - assertEquals(1.0, vector(1.0, 0.0) dot vector(1.0, 0.0)) - assertEquals(-2.0, vector(0.0, 1.0) dot vector(1.0, -2.0)) - assertEquals(2.0, vector(1.0, 1.0) dot vector(1.0, 1.0)) - assertEquals(4.001001, vector(-2.0, 1.001) dot vector(-2.0, 0.001)) - - assertEquals(-4.998, vector(1.0, 2.0) dot vector(-5.0, 0.001)) - } - } - - @Test - fun add() { - with(Euclidean2DSpace) { - assertVectorEquals( - vector(-2.0, 0.001), - vector(-2.0, 0.001) + zero - ) - assertVectorEquals( - vector(-3.0, 3.001), - vector(2.0, 3.0) + vector(-5.0, 0.001) - ) - } - } - - @Test - fun multiply() { - with(Euclidean2DSpace) { - assertVectorEquals(vector(-4.0, 0.0), vector(-2.0, 0.0) * 2) - assertVectorEquals(vector(4.0, 0.0), vector(-2.0, 0.0) * -2) - assertVectorEquals(vector(300.0, 0.0003), vector(100.0, 0.0001) * 3) - } - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt deleted file mode 100644 index 20e112ad1..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class Euclidean3DSpaceTest { - @Test - fun zero() { - assertVectorEquals(Euclidean3DSpace.vector(0.0, 0.0, 0.0), Euclidean3DSpace.zero) - } - - @Test - fun distance() { - with(Euclidean3DSpace) { - assertEquals(0.0, zero.distanceTo(zero)) - assertEquals(1.0, zero.distanceTo(vector(1.0, 0.0, 0.0))) - assertEquals(kotlin.math.sqrt(5.000001), vector(1.0, -2.0, 0.001).distanceTo(zero)) - assertEquals(0.0, vector(1.0, -2.0, 0.001).distanceTo(vector(1.0, -2.0, 0.001))) - assertEquals(0.0, vector(1.0, 0.0, 0.0).distanceTo(vector(1.0, 0.0, 0.0))) - assertEquals(kotlin.math.sqrt(2.0), vector(1.0, 0.0, 0.0).distanceTo(vector(1.0, 1.0, 1.0))) - assertEquals(3.1622778182822584, vector(0.0, 1.0, 0.0).distanceTo(vector(1.0, -2.0, 0.001))) - assertEquals(0.0, vector(1.0, -2.0, 0.001).distanceTo(vector(1.0, -2.0, 0.001))) - assertEquals(9.695050335093676, vector(1.0, 2.0, 3.0).distanceTo(vector(7.0, -5.0, 0.001))) - } - } - - @Test - fun norm() { - with(Euclidean3DSpace) { - assertEquals(0.0, zero.norm()) - assertEquals(1.0, vector(1.0, 0.0, 0.0).norm()) - assertEquals(kotlin.math.sqrt(3.0), vector(1.0, 1.0, 1.0).norm()) - assertEquals(kotlin.math.sqrt(5.000001), vector(1.0, -2.0, 0.001).norm()) - } - } - - @Test - fun dotProduct() { - with(Euclidean3DSpace) { - assertEquals(0.0, zero dot zero) - assertEquals(0.0, zero dot vector(1.0, 0.0, 0.0)) - assertEquals(0.0, vector(1.0, -2.0, 0.001) dot zero) - - assertEquals(1.0, vector(1.0, 0.0, 0.0) dot vector(1.0, 0.0, 0.0)) - assertEquals(1.0, vector(1.0, 0.0, 0.0) dot vector(1.0, 1.0, 1.0)) - assertEquals(-2.0, vector(0.0, 1.0, 0.0) dot vector(1.0, -2.0, 0.001)) - assertEquals(3.0, vector(1.0, 1.0, 1.0) dot vector(1.0, 1.0, 1.0)) - assertEquals(5.000001, vector(1.0, -2.0, 0.001) dot vector(1.0, -2.0, 0.001)) - - assertEquals(-2.997, vector(1.0, 2.0, 3.0) dot vector(7.0, -5.0, 0.001)) - } - } - - @Test - fun add() = with(Euclidean3DSpace) { - assertVectorEquals( - vector(1.0, -2.0, 0.001), - vector(1.0, -2.0, 0.001) + zero - ) - assertVectorEquals( - vector(8.0, -3.0, 3.001), - vector(1.0, 2.0, 3.0) + vector(7.0, -5.0, 0.001) - ) - } - - @Test - fun multiply() = with(Euclidean3DSpace) { - assertVectorEquals(vector(2.0, -4.0, 0.0), vector(1.0, -2.0, 0.0) * 2) - } - - @Test - fun vectorProduct() = with(Euclidean3DSpace) { - assertVectorEquals(zAxis, vectorProduct(xAxis, yAxis)) - assertVectorEquals(zAxis, xAxis cross yAxis) - assertVectorEquals(-zAxis, vectorProduct(yAxis, xAxis)) - } - - @Test - fun doubleVectorProduct() = with(Euclidean3DSpace) { - val a = vector(1, 2, -3) - val b = vector(-1, 0, 1) - val c = vector(4, 5, 6) - - val res = a cross (b cross c) - val expected = b * (a dot c) - c * (a dot b) - assertVectorEquals(expected, res) - } - -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt deleted file mode 100644 index cc74b06e3..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import kotlin.test.Test -import kotlin.test.assertTrue - -internal class ProjectionAlongTest { - @Test - fun projectionIntoYEqualsX() { - with(Euclidean2DSpace) { - val normal = vector(-2.0, 2.0) - val base = vector(2.3, 2.3) - - assertVectorEquals(zero, projectAlong(zero, normal, base)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - val d = (y - x) / 2.0 - assertVectorEquals(vector(x + d, y - d), projectAlong(vector(x, y), normal, base)) - } - } - } - - @Test - fun projectionOntoLine() { - with(Euclidean2DSpace) { - val a = 5.0 - val b = -3.0 - val c = -15.0 - val normal = vector(-5.0, 3.0) - val base = vector(3.0, 0.0) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - val xProj = (b * (b * x - a * y) - a * c) / (a * a + b * b) - val yProj = (a * (-b * x + a * y) - b * c) / (a * a + b * b) - assertVectorEquals(vector(xProj, yProj), projectAlong(vector(x, y), normal, base)) - } - } - } - - @Test - fun projectOntoPlane() = with(Euclidean3DSpace){ - val normal = vector(1.0, 3.5, 0.07) - val base = vector(2.0, -0.0037, 11.1111) - - with(Euclidean3DSpace) { - val testDomain = (-10.0..10.0).generateList(0.43) - for (x in testDomain) { - for (y in testDomain) { - for (z in testDomain) { - val v = vector(x, y, z) - val result = projectAlong(v, normal, base) - - // assert that result is on plane - assertTrue(isOrthogonal(result - base, normal)) - // assert that PV vector is collinear to normal vector - assertTrue(isCollinear(v - result, normal)) - } - } - } - } - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt deleted file mode 100644 index 7c6c105cf..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import kotlin.test.Test -import kotlin.test.assertTrue - -internal class ProjectionOntoLineTest { - @Test - fun projectionIntoOx() { - with(Euclidean2DSpace) { - val ox = Line(zero, vector(1.0, 0.0)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - assertVectorEquals(vector(x, 0.0), projectToLine(vector(x, y), ox)) - } - } - } - - @Test - fun projectionIntoOy() { - with(Euclidean2DSpace) { - val line = Line(zero, vector(0.0, 1.0)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - assertVectorEquals(vector(0.0, y), projectToLine(vector(x, y), line)) - } - } - } - - @Test - fun projectionIntoYEqualsX() { - with(Euclidean2DSpace) { - val line = Line(zero, vector(1.0, 1.0)) - - assertVectorEquals(zero, projectToLine(zero, line)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - val d = (y - x) / 2.0 - assertVectorEquals(vector(x + d, y - d), projectToLine(vector(x, y), line)) - } - } - } - - @Test - fun projectionOntoLine2d() { - with(Euclidean2DSpace) { - val a = 5.0 - val b = -3.0 - val c = -15.0 - val line = Line(vector(3.0, 0.0), vector(3.0, 5.0)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - val xProj = (b * (b * x - a * y) - a * c) / (a * a + b * b) - val yProj = (a * (-b * x + a * y) - b * c) / (a * a + b * b) - assertVectorEquals(vector(xProj, yProj), projectToLine(vector(x, y), line)) - } - } - } - - @Test - fun projectionOntoLine3d() = with(Euclidean3DSpace) { - val line = Line( - base = vector(1.0, 3.5, 0.07), - direction = vector(2.0, -0.0037, 11.1111) - ) - - - val testDomain = (-10.0..10.0).generateList(0.43) - for (x in testDomain) { - for (y in testDomain) { - for (z in testDomain) { - val v = vector(x, y, z) - val result = projectToLine(v, line) - - // assert that result is on the line - assertTrue(isCollinear(result - line.start, line.direction)) - // assert that PV vector is orthogonal to direction vector - assertTrue(isOrthogonal(v - result, line.direction)) - } - } - } - - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt deleted file mode 100644 index 6177382a2..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import space.kscience.kmath.complex.Quaternion -import space.kscience.kmath.complex.normalized -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.testutils.assertBufferEquals -import kotlin.test.Test - -class RotationTest { - - @Test - fun differentRotations() = with(Euclidean3DSpace) { - val vector = vector(1.0, 1.0, 1.0) - val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized() - val rotatedByQ = rotate(vector, q) - val matrix = q.toRotationMatrix() - val rotatedByM = rotate(vector, matrix) - - assertBufferEquals(rotatedByQ, rotatedByM, 1e-4) - } - - @Test - fun matrixConversion() { - - val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized() - - val matrix = q.toRotationMatrix() - - assertBufferEquals(q, Quaternion.fromRotationMatrix(matrix)) - } - - @Test - fun fromRotation() { - val q = Quaternion.fromRotation(0.3.radians, Euclidean3DSpace.vector(1.0, 1.0, 1.0)) - - assertBufferEquals(DoubleBuffer(0.9887711, 0.0862781, 0.0862781, 0.0862781), q) - } - - @Test - fun fromEuler() { - val q = Quaternion.fromEuler(0.1.radians, 0.2.radians, 0.3.radians, RotationOrder.ZXY) - - assertBufferEquals(DoubleBuffer(0.9818562, 0.0342708, 0.1060205, 0.1534393), q) - } -} \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt deleted file mode 100644 index 0db06f4c8..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - - -import space.kscience.kmath.operations.toList -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class Vector2DTest { - private val vector = Euclidean2DSpace.vector(1.0, -7.999) - - @Test - fun size() { - assertEquals(2, vector.size) - } - - @Test - fun get() { - assertEquals(1.0, vector[0]) - assertEquals(-7.999, vector[1]) - } - - @Test - fun iterator() { - assertEquals(listOf(1.0, -7.999), vector.toList()) - } - - @Test - fun x() { - assertEquals(1.0, vector.x) - } - - @Test - fun y() { - assertEquals(-7.999, vector.y) - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt deleted file mode 100644 index 1c8607838..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import space.kscience.kmath.operations.toList -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class Vector3DTest { - private val vector = Euclidean3DSpace.vector(1.0, -7.999, 0.001) - - @Test - fun size() { - assertEquals(3, vector.size) - } - - @Test - fun get() { - assertEquals(1.0, vector[0]) - assertEquals(-7.999, vector[1]) - assertEquals(0.001, vector[2]) - } - - @Test - fun iterator() { - assertEquals(listOf(1.0, -7.999, 0.001), vector.toList()) - } - - @Test - fun x() { - assertEquals(1.0, vector.x) - } - - @Test - fun y() { - assertEquals(-7.999, vector.y) - } - - @Test - fun z() { - assertEquals(0.001, vector.z) - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt deleted file mode 100644 index c62af3cd3..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.geometry - -import kotlin.math.abs -import kotlin.test.assertEquals - -fun ClosedRange.generateList(step: Double): List = generateSequence(start) { previous -> - if (previous == Double.POSITIVE_INFINITY) return@generateSequence null - val next = previous + step - if (next > endInclusive) null else next -}.toList() - -fun grid( - xRange: ClosedRange, - yRange: ClosedRange, - step: Double -): List> { - val xs = xRange.generateList(step) - val ys = yRange.generateList(step) - - return xs.flatMap { x -> ys.map { y -> x to y } } -} - -fun assertVectorEquals(expected: DoubleVector2D, actual: DoubleVector2D, absoluteTolerance: Double = 1e-6) { - assertEquals(expected.x, actual.x, absoluteTolerance) - assertEquals(expected.y, actual.y, absoluteTolerance) -} - -fun assertVectorEquals(expected: DoubleVector3D, actual: DoubleVector3D, absoluteTolerance: Double = 1e-6) { - assertEquals(expected.x, actual.x, absoluteTolerance) - assertEquals(expected.y, actual.y, absoluteTolerance) - assertEquals(expected.z, actual.z, absoluteTolerance) -} - -fun GeometrySpace.isCollinear(a: V, b: V, absoluteTolerance: Double = 1e-6): Boolean { - val aDist = a.distanceTo(zero) - val bDist = b.distanceTo(zero) - return abs(aDist) < absoluteTolerance || abs(bDist) < absoluteTolerance || abs(abs((a dot b) / (aDist * bDist)) - 1) < absoluteTolerance -} - -fun GeometrySpace.isOrthogonal(a: V, b: V, absoluteTolerance: Double = 1e-6): Boolean = - abs(a dot b) < absoluteTolerance - -fun Double.equalFloat(other: Double, maxFloatDelta: Double = 0.000001): - Boolean = kotlin.math.abs(this - other) < maxFloatDelta \ No newline at end of file diff --git a/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt b/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt deleted file mode 100644 index 5fcd2b23e..000000000 --- a/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -import space.kscience.kmath.geometry.GeometrySpace -import space.kscience.kmath.geometry.Line -import space.kscience.kmath.geometry.LineSegment -import space.kscience.kmath.geometry.Vector -import space.kscience.kmath.operations.Group - -/** - * Get a line, containing this [LineSegment] - */ -context(Group) public val LineSegment.line: Line get() = Line(begin, end - begin) - -/** - * Get a length of a line segment - */ -context(GeometrySpace) public val LineSegment.length: Double get() = norm(end - begin) \ No newline at end of file diff --git a/kmath-histograms/README.md b/kmath-histograms/README.md deleted file mode 100644 index bc7f0fa5b..000000000 --- a/kmath-histograms/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-histograms - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-histograms:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-histograms:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-histograms:0.4.0-dev-1") -} -``` diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 33704c29e..024e34076 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -1,31 +1,32 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity + plugins { - id("space.kscience.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") } -kscience{ - jvm() - js() - native() +kscience { + useAtomic() } -//apply(plugin = "kotlinx-atomicfu") - kotlin.sourceSets { commonMain { dependencies { api(project(":kmath-core")) - api(spclibs.atomicfu) } } commonTest { dependencies { implementation(project(":kmath-for-real")) - implementation(projects.kmath.kmathStat) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0") } } } readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE + maturity = Maturity.PROTOTYPE } diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt index 43ed24c70..3e5d93768 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -8,7 +8,7 @@ package space.kscience.kmath.histogram import kotlinx.atomicfu.atomic import kotlinx.atomicfu.getAndUpdate import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Group +import space.kscience.kmath.operations.Ring /** * Common representation for atomic counters @@ -18,8 +18,7 @@ public interface Counter { public val value: T public companion object { - public fun ofDouble(): ObjectCounter = ObjectCounter(DoubleField) - public fun of(group: Group): ObjectCounter = ObjectCounter(group) + public fun real(): ObjectCounter = ObjectCounter(DoubleField) } } @@ -33,16 +32,6 @@ public class IntCounter : Counter { override val value: Int get() = innerValue.value } -public operator fun IntCounter.inc(): IntCounter { - add(1) - return this -} - -public operator fun IntCounter.dec(): IntCounter { - add(-1) - return this -} - public class LongCounter : Counter { private val innerValue = atomic(0L) @@ -53,17 +42,7 @@ public class LongCounter : Counter { override val value: Long get() = innerValue.value } -public operator fun LongCounter.inc(): LongCounter { - add(1L) - return this -} - -public operator fun LongCounter.dec(): LongCounter { - add(-1L) - return this -} - -public class ObjectCounter(private val group: Group) : Counter { +public class ObjectCounter(public val group: Ring) : Counter { private val innerValue = atomic(group.zero) override fun add(delta: T) { diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt new file mode 100644 index 000000000..e792ef767 --- /dev/null +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt @@ -0,0 +1,130 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.histogram + +import space.kscience.kmath.domains.Domain +import space.kscience.kmath.domains.HyperSquareDomain +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.* +import space.kscience.kmath.structures.* +import kotlin.math.floor + +public class DoubleHistogramSpace( + private val lower: Buffer, + private val upper: Buffer, + private val binNums: IntArray = IntArray(lower.size) { 20 }, +) : IndexedHistogramSpace { + + init { + // argument checks + require(lower.size == upper.size) { "Dimension mismatch in histogram lower and upper limits." } + require(lower.size == binNums.size) { "Dimension mismatch in bin count." } + require(!lower.indices.any { upper[it] - lower[it] < 0 }) { "Range for one of axis is not strictly positive" } + } + + public val dimension: Int get() = lower.size + + private val shape = IntArray(binNums.size) { binNums[it] + 2 } + override val histogramValueSpace: DoubleFieldND = AlgebraND.real(*shape) + + override val strides: Strides get() = histogramValueSpace.strides + private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] } + + /** + * Get internal [StructureND] bin index for given axis + */ + private fun getIndex(axis: Int, value: Double): Int = when { + value >= upper[axis] -> binNums[axis] + 1 // overflow + value < lower[axis] -> 0 // underflow + else -> floor((value - lower[axis]) / binSize[axis]).toInt() + } + + override fun getIndex(point: Buffer): IntArray = IntArray(dimension) { + getIndex(it, point[it]) + } + + @OptIn(UnstableKMathAPI::class) + override fun getDomain(index: IntArray): Domain { + val lowerBoundary = index.mapIndexed { axis, i -> + when (i) { + 0 -> Double.NEGATIVE_INFINITY + strides.shape[axis] - 1 -> upper[axis] + else -> lower[axis] + (i.toDouble()) * binSize[axis] + } + }.asBuffer() + + val upperBoundary = index.mapIndexed { axis, i -> + when (i) { + 0 -> lower[axis] + strides.shape[axis] - 1 -> Double.POSITIVE_INFINITY + else -> lower[axis] + (i.toDouble() + 1) * binSize[axis] + } + }.asBuffer() + + return HyperSquareDomain(lowerBoundary, upperBoundary) + } + + + override fun produceBin(index: IntArray, value: Double): Bin { + val domain = getDomain(index) + return DomainBin(domain, value) + } + + override fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram { + val ndCounter = StructureND.auto(strides) { Counter.real() } + val hBuilder = HistogramBuilder { point, value -> + val index = getIndex(point) + ndCounter[index].add(value.toDouble()) + } + hBuilder.apply(builder) + val values: BufferND = ndCounter.mapToBuffer { it.value } + return IndexedHistogram(this, values) + } + + override fun IndexedHistogram.unaryMinus(): IndexedHistogram = this * (-1) + + public companion object { + /** + * Use it like + * ``` + *FastHistogram.fromRanges( + * (-1.0..1.0), + * (-1.0..1.0) + *) + *``` + */ + public fun fromRanges(vararg ranges: ClosedFloatingPointRange): DoubleHistogramSpace = DoubleHistogramSpace( + ranges.map(ClosedFloatingPointRange::start).asBuffer(), + ranges.map(ClosedFloatingPointRange::endInclusive).asBuffer() + ) + + /** + * Use it like + * ``` + *FastHistogram.fromRanges( + * (-1.0..1.0) to 50, + * (-1.0..1.0) to 32 + *) + *``` + */ + public fun fromRanges(vararg ranges: Pair, Int>): DoubleHistogramSpace = + DoubleHistogramSpace( + ListBuffer( + ranges + .map(Pair, Int>::first) + .map(ClosedFloatingPointRange::start) + ), + + ListBuffer( + ranges + .map(Pair, Int>::first) + .map(ClosedFloatingPointRange::endInclusive) + ), + + ranges.map(Pair, Int>::second).toIntArray() + ) + } +} \ No newline at end of file diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt index a4ae6d935..fcb5e96dc 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -11,25 +11,16 @@ import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer /** - * The binned data element. Could be a histogram bin with a number of counts or an artificial construct. + * The binned data element. Could be a histogram bin with a number of counts or an artificial construct */ -public interface Bin : Domain { +public interface Bin : Domain { /** * The value of this bin. */ - public val binValue: V + public val value: Number } -/** - * A simple histogram bin based on domain - */ -public data class DomainBin, D : Domain, out V>( - public val domain: D, - override val binValue: V, -) : Bin, Domain by domain - - -public interface Histogram> { +public interface Histogram> { /** * Find existing bin, corresponding to given coordinates */ @@ -41,38 +32,29 @@ public interface Histogram> { public val dimension: Int public val bins: Iterable - - public companion object { - //A discoverability root - } } -public interface HistogramBuilder { +public fun interface HistogramBuilder { /** - * The default value increment for a bin + * Increment appropriate bin */ - public val defaultValue: V - - /** - * Increment appropriate bin with given value - */ - public fun putValue(point: Point, value: V = defaultValue) + public fun putValue(point: Point, value: Number) } -public fun HistogramBuilder.put(point: Point): Unit = putValue(point) +public fun > HistogramBuilder.put(point: Point): Unit = putValue(point, 1.0) -public fun HistogramBuilder.put(vararg point: T): Unit = put(point.asBuffer()) +public fun HistogramBuilder.put(vararg point: T): Unit = put(point.asBuffer()) -public fun HistogramBuilder.put(vararg point: Number): Unit = +public fun HistogramBuilder.put(vararg point: Number): Unit = put(DoubleBuffer(point.map { it.toDouble() }.toDoubleArray())) -public fun HistogramBuilder.put(vararg point: Double): Unit = put(DoubleBuffer(point)) -public fun HistogramBuilder.fill(sequence: Iterable>): Unit = sequence.forEach { put(it) } +public fun HistogramBuilder.put(vararg point: Double): Unit = put(DoubleBuffer(point)) +public fun HistogramBuilder.fill(sequence: Iterable>): Unit = sequence.forEach { put(it) } /** * Pass a sequence builder into histogram */ -public fun HistogramBuilder.fill(block: suspend SequenceScope>.() -> Unit): Unit = +public fun HistogramBuilder.fill(block: suspend SequenceScope>.() -> Unit): Unit = fill(sequence(block).asIterable()) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt deleted file mode 100644 index f50610a17..000000000 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.histogram - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.domains.Domain1D -import space.kscience.kmath.domains.center -import space.kscience.kmath.linear.Point -import space.kscience.kmath.operations.asSequence -import space.kscience.kmath.structures.Buffer - - -/** - * A univariate bin based on a range - * - * @property binValue The value of histogram including weighting - */ -@UnstableKMathAPI -public data class Bin1D, out V>( - public val domain: Domain1D, - override val binValue: V, -) : Bin, ClosedRange by domain.range { - - override val dimension: Int get() = 1 - - override fun contains(point: Buffer): Boolean = point.size == 1 && contains(point[0]) -} - -@OptIn(UnstableKMathAPI::class) -public interface Histogram1D, V> : Histogram> { - override val dimension: Int get() = 1 - public operator fun get(value: T): Bin1D? - override operator fun get(point: Buffer): Bin1D? = get(point[0]) -} - -public interface Histogram1DBuilder : HistogramBuilder { - /** - * Thread safe put operation - */ - public fun putValue(at: T, value: V = defaultValue) - - override fun putValue(point: Point, value: V) { - require(point.size == 1) { "Only points with single value could be used in Histogram1D" } - putValue(point[0], value) - } -} - -@UnstableKMathAPI -public fun Histogram1DBuilder.fill(items: Iterable): Unit = - items.forEach(this::putValue) - -@UnstableKMathAPI -public fun Histogram1DBuilder.fill(array: DoubleArray): Unit = - array.forEach(this::putValue) - -@UnstableKMathAPI -public fun Histogram1DBuilder.fill(buffer: Buffer): Unit = - buffer.asSequence().forEach(this::putValue) - -@OptIn(UnstableKMathAPI::class) -public val Bin1D.center: Double get() = domain.center \ No newline at end of file diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt deleted file mode 100644 index 5fdc2ffb0..000000000 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.histogram - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.domains.Domain -import space.kscience.kmath.linear.Point -import space.kscience.kmath.nd.ColumnStrides -import space.kscience.kmath.nd.FieldOpsND -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke - -/** - * @param T the type of the argument space - * @param V the type of bin value - */ -public class HistogramND, D : Domain, V : Any>( - public val group: HistogramGroupND, - internal val values: StructureND, -) : Histogram> { - - @OptIn(PerformancePitfall::class) - override fun get(point: Point): DomainBin? { - val index = group.getIndexOrNull(point) ?: return null - return group.produceBin(index, values[index]) - } - - override val dimension: Int get() = group.shape.size - - @OptIn(PerformancePitfall::class) - override val bins: Iterable> - get() = ColumnStrides(group.shape).asSequence().map { - group.produceBin(it, values[it]) - }.asIterable() -} - -/** - * A space for producing histograms with values in a NDStructure - */ -public interface HistogramGroupND, D : Domain, V : Any> : - Group>, ScaleOperations> { - public val shape: ShapeND - public val valueAlgebraND: FieldOpsND //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape), - - /** - * Resolve index of the bin including given [point]. Return null if point is outside histogram area - */ - public fun getIndexOrNull(point: Point): IntArray? - - /** - * Get a bin domain represented by given index - */ - public fun getDomain(index: IntArray): Domain? - - public fun produceBin(index: IntArray, value: V): DomainBin - - public fun produce(builder: HistogramBuilder.() -> Unit): HistogramND - - override fun add(left: HistogramND, right: HistogramND): HistogramND { - require(left.group == this && right.group == this) { - "A histogram belonging to a different group cannot be operated." - } - return HistogramND(this, valueAlgebraND { left.values + right.values }) - } - - override fun scale(a: HistogramND, value: Double): HistogramND { - require(a.group == this) { "A histogram belonging to a different group cannot be operated." } - return HistogramND(this, valueAlgebraND { a.values * value }) - } - - override val zero: HistogramND get() = produce { } -} - diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt new file mode 100644 index 000000000..818d81ab0 --- /dev/null +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.histogram + +import space.kscience.kmath.domains.Domain +import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.FieldND +import space.kscience.kmath.nd.Strides +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.Group +import space.kscience.kmath.operations.GroupElement +import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.operations.invoke + +/** + * A simple histogram bin based on domain + */ +public data class DomainBin>( + public val domain: Domain, + public override val value: Number, +) : Bin, Domain by domain + +@OptIn(UnstableKMathAPI::class) +public class IndexedHistogram, V : Any>( + override val context: IndexedHistogramSpace, + public val values: StructureND, +) : Histogram>, GroupElement, IndexedHistogramSpace> { + + override fun get(point: Point): Bin? { + val index = context.getIndex(point) ?: return null + return context.produceBin(index, values[index]) + } + + override val dimension: Int get() = context.strides.shape.size + + override val bins: Iterable> + get() = context.strides.indices().map { + context.produceBin(it, values[it]) + }.asIterable() + +} + +/** + * A space for producing histograms with values in a NDStructure + */ +public interface IndexedHistogramSpace, V : Any> + : Group>, ScaleOperations> { + //public val valueSpace: Space + public val strides: Strides + public val histogramValueSpace: FieldND //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape), + + /** + * Resolve index of the bin including given [point] + */ + public fun getIndex(point: Point): IntArray? + + /** + * Get a bin domain represented by given index + */ + public fun getDomain(index: IntArray): Domain? + + public fun produceBin(index: IntArray, value: V): Bin + + public fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram + + override fun add(a: IndexedHistogram, b: IndexedHistogram): IndexedHistogram { + require(a.context == this) { "Can't operate on a histogram produced by external space" } + require(b.context == this) { "Can't operate on a histogram produced by external space" } + return IndexedHistogram(this, histogramValueSpace { a.values + b.values }) + } + + override fun scale(a: IndexedHistogram, value: Double): IndexedHistogram { + require(a.context == this) { "Can't operate on a histogram produced by external space" } + return IndexedHistogram(this, histogramValueSpace { a.values * value }) + } + + override val zero: IndexedHistogram get() = produce { } +} + diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt deleted file mode 100644 index 154d35350..000000000 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.histogram - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.domains.DoubleDomain1D -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer -import kotlin.math.floor - -@OptIn(UnstableKMathAPI::class) -public class UniformHistogram1D( - public val group: UniformHistogram1DGroup, - internal val values: Map, -) : Histogram1D { - - private val startPoint get() = group.startPoint - private val binSize get() = group.binSize - - private fun produceBin(index: Int, value: V): Bin1D { - val domain = DoubleDomain1D((startPoint + index * binSize)..(startPoint + (index + 1) * binSize)) - return Bin1D(domain, value) - } - - override val bins: Iterable> get() = values.map { produceBin(it.key, it.value) } - - override fun get(value: Double): Bin1D? { - val index: Int = group.getIndex(value) - val v = values[index] - return v?.let { produceBin(index, it) } - } -} - -/** - * An algebra for uniform histograms in 1D real space - */ -public class UniformHistogram1DGroup( - public val valueAlgebra: A, - public val binSize: Double, - public val startPoint: Double = 0.0, -) : Group>, ScaleOperations> where A : Ring, A : ScaleOperations { - - override val zero: UniformHistogram1D = UniformHistogram1D(this, emptyMap()) - - /** - * Get index of a bin - */ - @PublishedApi - internal fun getIndex(at: Double): Int = floor((at - startPoint) / binSize).toInt() - - override fun add( - left: Histogram1D, - right: Histogram1D, - ): UniformHistogram1D = valueAlgebra { - val leftUniform = produceFrom(left) - val rightUniform = produceFrom(right) - val keys = leftUniform.values.keys + rightUniform.values.keys - UniformHistogram1D( - this@UniformHistogram1DGroup, - keys.associateWith { - (leftUniform.values[it] ?: valueAlgebra.zero) + (rightUniform.values[it] ?: valueAlgebra.zero) - } - ) - } - - override fun Histogram1D.unaryMinus(): UniformHistogram1D = valueAlgebra { - UniformHistogram1D(this@UniformHistogram1DGroup, produceFrom(this@unaryMinus).values.mapValues { -it.value }) - } - - override fun scale( - a: Histogram1D, - value: Double, - ): UniformHistogram1D = UniformHistogram1D( - this@UniformHistogram1DGroup, - produceFrom(a).values.mapValues { valueAlgebra.scale(it.value, value) } - ) - - /** - * Fill histogram. - */ - public inline fun produce(block: Histogram1DBuilder.() -> Unit): UniformHistogram1D { - val map = HashMap() - val builder = object : Histogram1DBuilder { - override val defaultValue: V get() = valueAlgebra.zero - - override fun putValue(at: Double, value: V) { - val index = getIndex(at) - map[index] = with(valueAlgebra) { (map[index] ?: zero) + one } - } - } - builder.block() - return UniformHistogram1D(this, map) - } - - /** - * Re-bin given histogram to be compatible if exiting bin fully falls inside existing bin, this bin value - * is increased by one. If not, all bins including values from this bin are increased by fraction - * (conserving the norming). - */ - @OptIn(UnstableKMathAPI::class) - public fun produceFrom( - histogram: Histogram1D, - ): UniformHistogram1D = if ((histogram as? UniformHistogram1D)?.group == this) { - histogram - } else { - val map = HashMap() - histogram.bins.forEach { bin -> - val range = bin.domain.range - val indexOfLeft = getIndex(range.start) - val indexOfRight = getIndex(range.endInclusive) - val numBins = indexOfRight - indexOfLeft + 1 - for (i in indexOfLeft..indexOfRight) { - map[indexOfLeft] = with(valueAlgebra) { - (map[indexOfLeft] ?: zero) + bin.binValue / numBins - } - } - } - UniformHistogram1D(this, map) - } -} - -public fun Histogram.Companion.uniform1D( - valueAlgebra: A, - binSize: Double, - startPoint: Double = 0.0, -): UniformHistogram1DGroup where A : Ring, A : ScaleOperations = - UniformHistogram1DGroup(valueAlgebra, binSize, startPoint) - -@UnstableKMathAPI -public fun UniformHistogram1DGroup.produce( - buffer: Buffer, -): UniformHistogram1D = produce { fill(buffer) } - -/** - * Map of bin centers to bin values - */ -@OptIn(UnstableKMathAPI::class) -public val UniformHistogram1D.binValues: Map - get() = bins.associate { it.center to it.binValue } - - -//TODO add normalized values inside Field-based histogram spaces with context receivers -///** -// * Map of bin centers to normalized bin values (bin size as normalization) -// */ -//@OptIn(UnstableKMathAPI::class) -//public val UniformHistogram1D.binValuesNormalized: Map -// get() = group.valueAlgebra { -// bins.associate { it.center to it.binValue / group.binSize } -// } \ No newline at end of file diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt deleted file mode 100644 index 61ce450a7..000000000 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.histogram - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.domains.HyperSquareDomain -import space.kscience.kmath.linear.Point -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.* -import kotlin.math.floor - -public typealias HyperSquareBin = DomainBin - -/** - * Multivariate histogram space for hyper-square real-field bins. - * @param valueBufferFactory is an optional parameter used to optimize buffer production. - */ -public class UniformHistogramGroupND>( - override val valueAlgebraND: FieldOpsND, - private val lower: Buffer, - private val upper: Buffer, - private val binNums: IntArray = IntArray(lower.size) { 20 }, - private val valueBufferFactory: BufferFactory = valueAlgebraND.elementAlgebra.bufferFactory, -) : HistogramGroupND { - - init { - // argument checks - require(lower.size == upper.size) { "Dimension mismatch in histogram lower and upper limits." } - require(lower.size == binNums.size) { "Dimension mismatch in bin count." } - require(!lower.indices.any { upper[it] - lower[it] < 0 }) { "Range for one of axis is not strictly positive" } - } - - public val dimension: Int get() = lower.size - - override val shape: ShapeND = ShapeND(IntArray(binNums.size) { binNums[it] + 2 }) - - private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] } - - /** - * Get internal [StructureND] bin index for given axis - */ - private fun getIndex(axis: Int, value: Double): Int = when { - value >= upper[axis] -> binNums[axis] + 1 // overflow - value < lower[axis] -> 0 // underflow - else -> floor((value - lower[axis]) / binSize[axis]).toInt() - } - - override fun getIndexOrNull(point: Buffer): IntArray = IntArray(dimension) { - getIndex(it, point[it]) - } - - override fun getDomain(index: IntArray): HyperSquareDomain { - val lowerBoundary = index.mapIndexed { axis, i -> - when (i) { - 0 -> Double.NEGATIVE_INFINITY - shape[axis] - 1 -> upper[axis] - else -> lower[axis] + (i.toDouble()) * binSize[axis] - } - }.asBuffer() - - val upperBoundary = index.mapIndexed { axis, i -> - when (i) { - 0 -> lower[axis] - shape[axis] - 1 -> Double.POSITIVE_INFINITY - else -> lower[axis] + (i.toDouble() + 1) * binSize[axis] - } - }.asBuffer() - - return HyperSquareDomain(lowerBoundary, upperBoundary) - } - - override fun produceBin(index: IntArray, value: V): HyperSquareBin { - val domain = getDomain(index) - return DomainBin(domain, value) - } - - - @OptIn(PerformancePitfall::class) - override fun produce( - builder: HistogramBuilder.() -> Unit, - ): HistogramND { - val ndCounter: BufferND> = - StructureND.buffered(shape) { Counter.of(valueAlgebraND.elementAlgebra) } - val hBuilder = object : HistogramBuilder { - override val defaultValue: V get() = valueAlgebraND.elementAlgebra.one - - override fun putValue(point: Point, value: V) = with(valueAlgebraND.elementAlgebra) { - val index = getIndexOrNull(point) - ndCounter[index].add(value) - } - } - hBuilder.apply(builder) - val values: BufferND = BufferND(ndCounter.indices, ndCounter.buffer.mapToBuffer(valueBufferFactory) { it.value }) - - return HistogramND(this, values) - } - - override fun HistogramND.unaryMinus(): HistogramND = - this * (-1) -} - -/** - * Use it like - * ``` - *FastHistogram.fromRanges( - * (-1.0..1.0), - * (-1.0..1.0) - *) - *``` - */ -public fun > Histogram.Companion.uniformNDFromRanges( - valueAlgebraND: FieldOpsND, - vararg ranges: ClosedFloatingPointRange, - bufferFactory: BufferFactory = valueAlgebraND.elementAlgebra.bufferFactory, -): UniformHistogramGroupND = UniformHistogramGroupND( - valueAlgebraND, - ranges.map(ClosedFloatingPointRange::start).asBuffer(), - ranges.map(ClosedFloatingPointRange::endInclusive).asBuffer(), - valueBufferFactory = bufferFactory -) - -public fun Histogram.Companion.uniformDoubleNDFromRanges( - vararg ranges: ClosedFloatingPointRange, -): UniformHistogramGroupND = - uniformNDFromRanges(DoubleFieldOpsND, *ranges, bufferFactory = ::DoubleBuffer) - - -/** - * Use it like - * ``` - *FastHistogram.fromRanges( - * (-1.0..1.0) to 50, - * (-1.0..1.0) to 32 - *) - *``` - */ -public fun > Histogram.Companion.uniformNDFromRanges( - valueAlgebraND: FieldOpsND, - vararg ranges: Pair, Int>, - bufferFactory: BufferFactory = valueAlgebraND.elementAlgebra.bufferFactory, -): UniformHistogramGroupND = UniformHistogramGroupND( - valueAlgebraND, - ListBuffer( - ranges - .map(Pair, Int>::first) - .map(ClosedFloatingPointRange::start) - ), - ListBuffer( - ranges - .map(Pair, Int>::first) - .map(ClosedFloatingPointRange::endInclusive) - ), - ranges.map(Pair, Int>::second).toIntArray(), - valueBufferFactory = bufferFactory -) - -public fun Histogram.Companion.uniformDoubleNDFromRanges( - vararg ranges: Pair, Int>, -): UniformHistogramGroupND = - uniformNDFromRanges(DoubleFieldOpsND, *ranges, bufferFactory = ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt index 54806c9fa..51f9dabc5 100644 --- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt +++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt @@ -1,15 +1,10 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:OptIn(UnstableKMathAPI::class) - package space.kscience.kmath.histogram -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.operations.invoke import space.kscience.kmath.real.DoubleVector import kotlin.random.Random @@ -18,14 +13,14 @@ import kotlin.test.* internal class MultivariateHistogramTest { @Test fun testSinglePutHistogram() { - val hSpace = Histogram.uniformDoubleNDFromRanges( + val hSpace = DoubleHistogramSpace.fromRanges( (-1.0..1.0), (-1.0..1.0) ) val histogram = hSpace.produce { put(0.55, 0.55) } - val bin = histogram.bins.find { it.binValue.toInt() > 0 } ?: fail() + val bin = histogram.bins.find { it.value.toInt() > 0 } ?: fail() assertTrue { bin.contains(DoubleVector(0.55, 0.55)) } assertTrue { bin.contains(DoubleVector(0.6, 0.5)) } assertFalse { bin.contains(DoubleVector(-0.55, 0.55)) } @@ -33,7 +28,7 @@ internal class MultivariateHistogramTest { @Test fun testSequentialPut() { - val hSpace = Histogram.uniformDoubleNDFromRanges( + val hSpace = DoubleHistogramSpace.fromRanges( (-1.0..1.0), (-1.0..1.0), (-1.0..1.0) @@ -48,13 +43,12 @@ internal class MultivariateHistogramTest { put(nextDouble(), nextDouble(), nextDouble()) } } - assertEquals(n, histogram.bins.sumOf { it.binValue.toInt() }) + assertEquals(n, histogram.bins.sumOf { it.value.toInt() }) } - @OptIn(PerformancePitfall::class) @Test fun testHistogramAlgebra() { - Histogram.uniformDoubleNDFromRanges( + DoubleHistogramSpace.fromRanges( (-1.0..1.0), (-1.0..1.0), (-1.0..1.0) @@ -75,14 +69,14 @@ internal class MultivariateHistogramTest { } val res = histogram1 - histogram2 assertTrue { - ColumnStrides(shape).asSequence().all { index -> + strides.indices().all { index -> res.values[index] <= histogram1.values[index] } } assertTrue { res.bins.count() >= histogram1.bins.count() } - assertEquals(0.0, res.bins.sumOf { it.binValue.toDouble() }) + assertEquals(0.0, res.bins.sumOf { it.value.toDouble() }) } } } \ No newline at end of file diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt deleted file mode 100644 index fa129fad6..000000000 --- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.histogram - -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runTest -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.stat.nextBuffer -import kotlin.native.concurrent.ThreadLocal -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(ExperimentalCoroutinesApi::class, UnstableKMathAPI::class) -internal class UniformHistogram1DTest { - - @Test - fun normal() = runTest { - val distribution = NormalDistribution(0.0, 1.0) - with(Histogram.uniform1D(DoubleField, 0.1)) { - val h1 = produce(distribution.nextBuffer(generator, 10000)) - - val h2 = produce(distribution.nextBuffer(generator, 50000)) - - val h3 = h1 + h2 - - assertEquals(60000, h3.bins.sumOf { it.binValue }.toInt()) - } - } - - @Test - fun rebinDown() = runTest { - val h1 = Histogram.uniform1D(DoubleField, 0.01).produce(generator.nextDoubleBuffer(10000)) - val h2 = Histogram.uniform1D(DoubleField, 0.03).produceFrom(h1) - - assertEquals(10000, h2.bins.sumOf { it.binValue }.toInt()) - } - - @Test - fun rebinUp() = runTest { - val h1 = Histogram.uniform1D(DoubleField, 0.03).produce(generator.nextDoubleBuffer(10000)) - val h2 = Histogram.uniform1D(DoubleField, 0.01).produceFrom(h1) - - assertEquals(10000, h2.bins.sumOf { it.binValue }.toInt()) - } - - @ThreadLocal - companion object { - private val generator = RandomGenerator.default(123) - } -} \ No newline at end of file diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt deleted file mode 100644 index 772db7df3..000000000 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.histogram - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.domains.DoubleDomain1D -import space.kscience.kmath.domains.center -import space.kscience.kmath.misc.sorted -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.first -import space.kscience.kmath.structures.indices -import space.kscience.kmath.structures.last -import java.util.* - -private fun > TreeMap.getBin(value: Double): B? { - // check ceiling entry and return it if it is what needed - val ceil = ceilingEntry(value)?.value - if (ceil != null && value in ceil) return ceil - //check floor entry - val floor = floorEntry(value)?.value - if (floor != null && value in floor) return floor - //neither is valid, not found - return null -} - -//public data class ValueAndError(val value: Double, val error: Double) -// -//public typealias WeightedBin1D = Bin1D - -/** - * A histogram based on a tree map of values - */ -public class TreeHistogram( - private val binMap: TreeMap>, -) : Histogram1D { - override fun get(value: Double): Bin1D? = binMap.getBin(value) - override val bins: Collection> get() = binMap.values -} - -/** - * A space for univariate histograms with variable bin borders based on a tree map - */ -public class TreeHistogramGroup( - public val valueAlgebra: A, - @PublishedApi internal val binFactory: (Double) -> DoubleDomain1D, -) : Group>, ScaleOperations> where A : Ring, A : ScaleOperations { - - internal inner class DomainCounter(val domain: DoubleDomain1D, val counter: Counter = Counter.of(valueAlgebra)) : - ClosedRange by domain.range - - @PublishedApi - internal inner class TreeHistogramBuilder : Histogram1DBuilder { - - override val defaultValue: V get() = valueAlgebra.one - - private val bins: TreeMap = TreeMap() - - private fun createBin(value: Double): DomainCounter { - val binDefinition: DoubleDomain1D = binFactory(value) - val newBin = DomainCounter(binDefinition) - synchronized(this) { - bins[binDefinition.center] = newBin - } - return newBin - } - - /** - * Thread safe put operation - */ - override fun putValue(at: Double, value: V) { - (bins.getBin(at) ?: createBin(at)).counter.add(value) - } - - fun build(): TreeHistogram { - val map = bins.mapValuesTo(TreeMap>()) { (_, binCounter) -> - Bin1D(binCounter.domain, binCounter.counter.value) - } - return TreeHistogram(map) - } - } - - public inline fun produce(block: Histogram1DBuilder.() -> Unit): TreeHistogram = - TreeHistogramBuilder().apply(block).build() - - override fun add( - left: TreeHistogram, - right: TreeHistogram, - ): TreeHistogram { - val bins = TreeMap>().apply { - (left.bins.map { it.domain } union right.bins.map { it.domain }).forEach { def -> - put( - def.center, - Bin1D( - def, - with(valueAlgebra) { - (left[def.center]?.binValue ?: zero) + (right[def.center]?.binValue ?: zero) - } - ) - ) - } - } - return TreeHistogram(bins) - } - - override fun scale(a: TreeHistogram, value: Double): TreeHistogram { - val bins = TreeMap>().apply { - a.bins.forEach { bin -> - put( - bin.domain.center, - Bin1D(bin.domain, valueAlgebra.scale(bin.binValue, value)) - ) - } - } - - return TreeHistogram(bins) - } - - override fun TreeHistogram.unaryMinus(): TreeHistogram = this * (-1) - - override val zero: TreeHistogram = produce { } -} - - -///** -// * Build and fill a histogram with custom borders. Returns a read-only histogram. -// */ -//public inline fun Histogram.custom( -// borders: DoubleArray, -// builder: Histogram1DBuilder.() -> Unit, -//): TreeHistogram = custom(borders).fill(builder) -// -// -///** -// * Build and fill a [DoubleHistogram1D]. Returns a read-only histogram. -// */ -//public fun uniform( -// binSize: Double, -// start: Double = 0.0, -//): TreeHistogramSpace = TreeHistogramSpace { value -> -// val center = start + binSize * floor((value - start) / binSize + 0.5) -// DoubleDomain1D((center - binSize / 2)..(center + binSize / 2)) -//} - -/** - * Create a histogram group with custom cell borders - */ -public fun Histogram.Companion.custom1D( - valueAlgebra: A, - borders: Buffer, -): TreeHistogramGroup where A : Ring, A : ScaleOperations { - val sorted = borders.sorted() - - return TreeHistogramGroup(valueAlgebra) { value -> - when { - value <= sorted.first() -> DoubleDomain1D( - Double.NEGATIVE_INFINITY..sorted.first() - ) - - value > sorted.last() -> DoubleDomain1D( - sorted.last()..Double.POSITIVE_INFINITY - ) - - else -> { - val index = sorted.indices.first { value <= sorted[it] } - val left = sorted[index - 1] - val right = sorted[index] - DoubleDomain1D(left..right) - } - } - } -} \ No newline at end of file diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt new file mode 100644 index 000000000..5a217f6c2 --- /dev/null +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt @@ -0,0 +1,164 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.histogram + +import space.kscience.kmath.domains.UnivariateDomain +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Group +import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.structures.Buffer +import java.util.* +import kotlin.math.abs +import kotlin.math.floor +import kotlin.math.sqrt + +private fun > TreeMap.getBin(value: Double): B? { + // check ceiling entry and return it if it is what needed + val ceil = ceilingEntry(value)?.value + if (ceil != null && value in ceil) return ceil + //check floor entry + val floor = floorEntry(value)?.value + if (floor != null && value in floor) return floor + //neither is valid, not found + return null +} + +@UnstableKMathAPI +public class TreeHistogram( + override val context: TreeHistogramSpace, + private val binMap: TreeMap, +) : UnivariateHistogram { + override fun get(value: Double): UnivariateBin? = binMap.getBin(value) + override val dimension: Int get() = 1 + override val bins: Collection get() = binMap.values +} + +/** + * A space for univariate histograms with variable bin borders based on a tree map + */ +@UnstableKMathAPI +public class TreeHistogramSpace( + public val binFactory: (Double) -> UnivariateDomain, +) : Group, ScaleOperations { + + private class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : + ClosedFloatingPointRange by domain.range + + public fun produce(builder: UnivariateHistogramBuilder.() -> Unit): UnivariateHistogram { + val bins: TreeMap = TreeMap() + val hBuilder = object : UnivariateHistogramBuilder { + + fun get(value: Double): BinCounter? = bins.getBin(value) + + fun createBin(value: Double): BinCounter { + val binDefinition = binFactory(value) + val newBin = BinCounter(binDefinition) + synchronized(this) { bins[binDefinition.center] = newBin } + return newBin + } + + /** + * Thread safe put operation + */ + override fun putValue(at: Double, value: Double) { + (get(at) ?: createBin(at)).apply { + counter.add(value) + } + } + + override fun putValue(point: Buffer, value: Number) { + put(point[0], value.toDouble()) + } + } + hBuilder.apply(builder) + val resBins = TreeMap() + bins.forEach { (key, binCounter) -> + val count = binCounter.counter.value + resBins[key] = UnivariateBin(binCounter.domain, count, sqrt(count)) + } + return TreeHistogram(this, resBins) + } + + override fun add( + a: UnivariateHistogram, + b: UnivariateHistogram, + ): UnivariateHistogram { + require(a.context == this) { "Histogram $a does not belong to this context" } + require(b.context == this) { "Histogram $b does not belong to this context" } + val bins = TreeMap().apply { + (a.bins.map { it.domain } union b.bins.map { it.domain }).forEach { def -> + put(def.center, + UnivariateBin( + def, + value = (a[def.center]?.value ?: 0.0) + (b[def.center]?.value ?: 0.0), + standardDeviation = (a[def.center]?.standardDeviation + ?: 0.0) + (b[def.center]?.standardDeviation ?: 0.0) + ) + ) + } + } + return TreeHistogram(this, bins) + } + + override fun scale(a: UnivariateHistogram, value: Double): UnivariateHistogram { + val bins = TreeMap().apply { + a.bins.forEach { bin -> + put(bin.domain.center, + UnivariateBin( + bin.domain, + value = bin.value * value.toDouble(), + standardDeviation = abs(bin.standardDeviation * value.toDouble()) + ) + ) + } + } + + return TreeHistogram(this, bins) + } + + override fun UnivariateHistogram.unaryMinus(): UnivariateHistogram = this * (-1) + + override val zero: UnivariateHistogram = produce { } + + public companion object { + /** + * Build and fill a [UnivariateHistogram]. Returns a read-only histogram. + */ + public fun uniform( + binSize: Double, + start: Double = 0.0, + ): TreeHistogramSpace = TreeHistogramSpace { value -> + val center = start + binSize * floor((value - start) / binSize + 0.5) + UnivariateDomain((center - binSize / 2)..(center + binSize / 2)) + } + + /** + * Create a histogram with custom cell borders + */ + public fun custom(borders: DoubleArray): TreeHistogramSpace { + val sorted = borders.sortedArray() + + return TreeHistogramSpace { value -> + when { + value < sorted.first() -> UnivariateDomain( + Double.NEGATIVE_INFINITY..sorted.first() + ) + + value > sorted.last() -> UnivariateDomain( + sorted.last()..Double.POSITIVE_INFINITY + ) + + else -> { + val index = sorted.indices.first { value > sorted[it] } + val left = sorted[index] + val right = sorted[index + 1] + UnivariateDomain(left..right) + } + } + } + } + } +} \ No newline at end of file diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt new file mode 100644 index 000000000..645116ade --- /dev/null +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.histogram + +import space.kscience.kmath.domains.UnivariateDomain +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Group +import space.kscience.kmath.operations.GroupElement +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asSequence + + +@UnstableKMathAPI +public val UnivariateDomain.center: Double + get() = (range.endInclusive - range.start) / 2 + +/** + * A univariate bin based an a range + * @param value The value of histogram including weighting + * @param standardDeviation Standard deviation of the bin value. Zero or negative if not applicable + */ +@UnstableKMathAPI +public class UnivariateBin( + public val domain: UnivariateDomain, + override val value: Double, + public val standardDeviation: Double, +) : Bin, ClosedFloatingPointRange by domain.range { + + public override val dimension: Int get() = 1 + + public override fun contains(point: Buffer): Boolean = point.size == 1 && contains(point[0]) +} + +@OptIn(UnstableKMathAPI::class) +public interface UnivariateHistogram : Histogram, + GroupElement> { + public operator fun get(value: Double): UnivariateBin? + public override operator fun get(point: Buffer): UnivariateBin? = get(point[0]) + + public companion object { + /** + * Build and fill a [UnivariateHistogram]. Returns a read-only histogram. + */ + public fun uniform( + binSize: Double, + start: Double = 0.0, + builder: UnivariateHistogramBuilder.() -> Unit, + ): UnivariateHistogram = TreeHistogramSpace.uniform(binSize, start).produce(builder) + + /** + * Build and fill a histogram with custom borders. Returns a read-only histogram. + */ + public fun custom( + borders: DoubleArray, + builder: UnivariateHistogramBuilder.() -> Unit, + ): UnivariateHistogram = TreeHistogramSpace.custom(borders).produce(builder) + + } +} + +@UnstableKMathAPI +public interface UnivariateHistogramBuilder : HistogramBuilder { + /** + * Thread safe put operation + */ + public fun putValue(at: Double, value: Double = 1.0) + + override fun putValue(point: Buffer, value: Number) +} + +@UnstableKMathAPI +public fun UnivariateHistogramBuilder.fill(items: Iterable): Unit = items.forEach(this::putValue) + +@UnstableKMathAPI +public fun UnivariateHistogramBuilder.fill(array: DoubleArray): Unit = array.forEach(this::putValue) + +@UnstableKMathAPI +public fun UnivariateHistogramBuilder.fill(buffer: Buffer): Unit = buffer.asSequence().forEach(this::putValue) \ No newline at end of file diff --git a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt deleted file mode 100644 index b7c1f34ba..000000000 --- a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.histogram - -import org.junit.jupiter.api.Test -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.real.step -import kotlin.random.Random -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -@OptIn(UnstableKMathAPI::class) -class TreeHistogramTest { - - @Test - fun normalFill() { - val random = Random(123) - val histogram = Histogram.custom1D(DoubleField, 0.0..1.0 step 0.1).produce { - repeat(100_000) { - putValue(random.nextDouble()) - } - } - - assertTrue { histogram.bins.count() > 8} - assertEquals(100_000, histogram.bins.sumOf { it.binValue }.toInt()) - } -} \ No newline at end of file diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md deleted file mode 100644 index 47142f174..000000000 --- a/kmath-jafama/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Module kmath-jafama - -Integration with [Jafama](https://github.com/jeffhain/jafama). - - - [jafama-double](src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-jafama:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-jafama:0.4.0-dev-1") -} -``` - -## Example usage - -All the `DoubleField` uses can be replaced with `JafamaDoubleField` or `StrictJafamaDoubleField`. - -```kotlin -import space.kscience.kmath.jafama.* -import space.kscience.kmath.operations.* - -fun main() { - val a = 2.0 - val b = StrictJafamaDoubleField { exp(a) } - println(JafamaDoubleField { b + a }) - println(StrictJafamaDoubleField { ln(b) }) -} -``` - -## Performance - -According to KMath benchmarks on GraalVM, Jafama functions are slower than JDK math; however, there are indications that on Hotspot Jafama is a bit faster. - -> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**. diff --git a/kmath-jafama/build.gradle.kts b/kmath-jafama/build.gradle.kts deleted file mode 100644 index 5a77a97ed..000000000 --- a/kmath-jafama/build.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -plugins { - id("space.kscience.gradle.jvm") -} - -description = "Jafama integration module" - -dependencies { - api(project(":kmath-core")) - api("net.jafama:jafama:2.3.2") -} - -repositories { - mavenCentral() -} - -readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature("jafama-double", "src/main/kotlin/space/kscience/kmath/jafama/") { - "Double ExtendedField implementations based on Jafama" - } -} \ No newline at end of file diff --git a/kmath-jafama/docs/README-TEMPLATE.md b/kmath-jafama/docs/README-TEMPLATE.md deleted file mode 100644 index 54348467b..000000000 --- a/kmath-jafama/docs/README-TEMPLATE.md +++ /dev/null @@ -1,29 +0,0 @@ -# Module kmath-jafama - -Integration with [Jafama](https://github.com/jeffhain/jafama). - -${features} - -${artifact} - -## Example usage - -All the `DoubleField` uses can be replaced with `JafamaDoubleField` or `StrictJafamaDoubleField`. - -```kotlin -import space.kscience.kmath.jafama.* -import space.kscience.kmath.operations.* - -fun main() { - val a = 2.0 - val b = StrictJafamaDoubleField { exp(a) } - println(JafamaDoubleField { b + a }) - println(StrictJafamaDoubleField { ln(b) }) -} -``` - -## Performance - -According to KMath benchmarks on GraalVM, Jafama functions are slower than JDK math; however, there are indications that on Hotspot Jafama is a bit faster. - -${benchmarkJafamaDouble} diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt deleted file mode 100644 index f9b8287b4..000000000 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.jafama - -import net.jafama.FastMath -import net.jafama.StrictFastMath -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.Norm -import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.ScaleOperations - -/** - * A field for [Double] (using FastMath) without boxing. Does not produce appropriate field element. - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object JafamaDoubleField : ExtendedField, Norm, ScaleOperations { - override inline val zero: Double get() = 0.0 - override inline val one: Double get() = 1.0 - - override inline fun number(value: Number): Double = value.toDouble() - - override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = - when (operation) { - PowerOperations.POW_OPERATION -> ::power - else -> super.binaryOperationFunction(operation) - } - - override inline fun add(left: Double, right: Double): Double = left + right - - override inline fun multiply(left: Double, right: Double): Double = left * right - override inline fun divide(left: Double, right: Double): Double = left / right - - override inline fun scale(a: Double, value: Double): Double = a * value - - override inline fun sin(arg: Double): Double = FastMath.sin(arg) - override inline fun cos(arg: Double): Double = FastMath.cos(arg) - override inline fun tan(arg: Double): Double = FastMath.tan(arg) - override inline fun acos(arg: Double): Double = FastMath.acos(arg) - override inline fun asin(arg: Double): Double = FastMath.asin(arg) - override inline fun atan(arg: Double): Double = FastMath.atan(arg) - - override inline fun sinh(arg: Double): Double = FastMath.sinh(arg) - override inline fun cosh(arg: Double): Double = FastMath.cosh(arg) - override inline fun tanh(arg: Double): Double = FastMath.tanh(arg) - override inline fun asinh(arg: Double): Double = FastMath.asinh(arg) - override inline fun acosh(arg: Double): Double = FastMath.acosh(arg) - override inline fun atanh(arg: Double): Double = FastMath.atanh(arg) - - override inline fun sqrt(arg: Double): Double = FastMath.sqrt(arg) - override inline fun power(arg: Double, pow: Number): Double = FastMath.pow(arg, pow.toDouble()) - override inline fun exp(arg: Double): Double = FastMath.exp(arg) - override inline fun ln(arg: Double): Double = FastMath.log(arg) - - override inline fun norm(arg: Double): Double = FastMath.abs(arg) - - override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(arg: Double): Double = this + arg - override inline fun Double.minus(arg: Double): Double = this - arg - override inline fun Double.times(arg: Double): Double = this * arg - override inline fun Double.div(arg: Double): Double = this / arg -} - -/** - * A field for [Double] (using StrictMath) without boxing. Does not produce appropriate field element. - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object StrictJafamaDoubleField : ExtendedField, Norm, ScaleOperations { - override inline val zero: Double get() = 0.0 - override inline val one: Double get() = 1.0 - - override inline fun number(value: Number): Double = value.toDouble() - - override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = - when (operation) { - PowerOperations.POW_OPERATION -> ::power - else -> super.binaryOperationFunction(operation) - } - - override inline fun add(left: Double, right: Double): Double = left + right - - override inline fun multiply(left: Double, right: Double): Double = left * right - override inline fun divide(left: Double, right: Double): Double = left / right - - override inline fun scale(a: Double, value: Double): Double = a * value - - override inline fun sin(arg: Double): Double = StrictFastMath.sin(arg) - override inline fun cos(arg: Double): Double = StrictFastMath.cos(arg) - override inline fun tan(arg: Double): Double = StrictFastMath.tan(arg) - override inline fun acos(arg: Double): Double = StrictFastMath.acos(arg) - override inline fun asin(arg: Double): Double = StrictFastMath.asin(arg) - override inline fun atan(arg: Double): Double = StrictFastMath.atan(arg) - - override inline fun sinh(arg: Double): Double = StrictFastMath.sinh(arg) - override inline fun cosh(arg: Double): Double = StrictFastMath.cosh(arg) - override inline fun tanh(arg: Double): Double = StrictFastMath.tanh(arg) - override inline fun asinh(arg: Double): Double = StrictFastMath.asinh(arg) - override inline fun acosh(arg: Double): Double = StrictFastMath.acosh(arg) - override inline fun atanh(arg: Double): Double = StrictFastMath.atanh(arg) - - override inline fun sqrt(arg: Double): Double = StrictFastMath.sqrt(arg) - override inline fun power(arg: Double, pow: Number): Double = StrictFastMath.pow(arg, pow.toDouble()) - override inline fun exp(arg: Double): Double = StrictFastMath.exp(arg) - override inline fun ln(arg: Double): Double = StrictFastMath.log(arg) - - override inline fun norm(arg: Double): Double = StrictFastMath.abs(arg) - - override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(arg: Double): Double = this + arg - override inline fun Double.minus(arg: Double): Double = this - arg - override inline fun Double.times(arg: Double): Double = this * arg - override inline fun Double.div(arg: Double): Double = this / arg -} diff --git a/kmath-jupyter/README.md b/kmath-jupyter/README.md deleted file mode 100644 index 2b26878dc..000000000 --- a/kmath-jupyter/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-jupyter - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-jupyter:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-jupyter:0.4.0-dev-1") -} -``` diff --git a/kmath-jupyter/api/kmath-jupyter.api b/kmath-jupyter/api/kmath-jupyter.api deleted file mode 100644 index e625e22f7..000000000 --- a/kmath-jupyter/api/kmath-jupyter.api +++ /dev/null @@ -1,4 +0,0 @@ -public final class space/kscience/kmath/jupyter/KMathJupyterKt { - public static final fun toMst (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric; -} - diff --git a/kmath-jupyter/build.gradle.kts b/kmath-jupyter/build.gradle.kts deleted file mode 100644 index a0e217177..000000000 --- a/kmath-jupyter/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - id("space.kscience.gradle.jvm") - kotlin("jupyter.api") -} - -dependencies { - api(spclibs.kotlinx.html) - api(project(":kmath-ast")) - api(project(":kmath-complex")) - api(project(":kmath-for-real")) -} - -readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE -} - -tasks.processJupyterApiResources { - libraryProducers = listOf("space.kscience.kmath.jupyter.KMathJupyter") -} diff --git a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt deleted file mode 100644 index 944666c9e..000000000 --- a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.jupyter - -import kotlinx.html.Unsafe -import kotlinx.html.div -import kotlinx.html.stream.createHTML -import kotlinx.html.unsafe -import org.jetbrains.kotlinx.jupyter.api.DisplayResult -import org.jetbrains.kotlinx.jupyter.api.HTML -import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess -import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer -import space.kscience.kmath.ast.rendering.renderWithStringBuilder -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.Quaternion -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.MstRing -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.operations.asSequence -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer - -/** - * A function for conversion of number to MST for pretty print - */ -public fun Number.toMst(): MST.Numeric = MST.Numeric(this) - -@OptIn(UnstableKMathAPI::class) -internal class KMathJupyter : JupyterIntegration() { - private val mathRender = FeaturedMathRendererWithPostProcess.Default - private val syntaxRender = MathMLSyntaxRenderer - - private fun MST.toDisplayResult(): DisplayResult = HTML(createHTML().div { - unsafe { - +syntaxRender.renderWithStringBuilder(mathRender.render(this@toDisplayResult)) - } - }) - - private fun Unsafe.appendCellValue(it: Any?) { - when (it) { - is Number -> { - val s = StringBuilder() - syntaxRender.renderPart(mathRender.render(MST.Numeric(it)), s) - +s.toString() - } - - is MST -> { - val s = StringBuilder() - syntaxRender.renderPart(mathRender.render(it), s) - +s.toString() - } - - else -> { - +"" - +it.toString() - +"" - } - } - } - - @OptIn(PerformancePitfall::class) - override fun Builder.onLoaded() { - import( - "space.kscience.kmath.ast.*", - "space.kscience.kmath.ast.rendering.*", - "space.kscience.kmath.structures.*", - "space.kscience.kmath.operations.*", - "space.kscience.kmath.expressions.*", - "space.kscience.kmath.nd.*", - "space.kscience.kmath.misc.*", - "space.kscience.kmath.real.*", - ) - - import("space.kscience.kmath.jupyter.toMst") - - render { it.toDisplayResult() } - //render { MST.Numeric(it).toDisplayResult() } - - render> { structure -> - HTML(createHTML().div { - unsafe { - +"" - +"" - +"" - +"" - structure.rows.forEach { row -> - +"" - row.asSequence().forEach { - +"" - appendCellValue(it) - +"" - } - +"" - } - +"" - +"" - +"" - +"" - } - }) - } - - render> { buffer -> - HTML(createHTML().div { - unsafe { - +"" - +"" - +"" - +"" - buffer.asSequence().forEach { - +"" - +"" - appendCellValue(it) - +"" - +"" - } - +"" - +"" - +"" - +"" - } - }) - } - - render { - MstRing { - number(it.re) + number(it.im) * bindSymbol("i") - }.toDisplayResult() - } - - render { - MstRing { - number(it.w) + - number(it.x) * bindSymbol("i") + - number(it.x) * bindSymbol("j") + - number(it.x) * bindSymbol("k") - }.toDisplayResult() - } - } -} diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md deleted file mode 100644 index f1a918b4b..000000000 --- a/kmath-kotlingrad/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Module kmath-kotlingrad - -[Kotlin∇](https://github.com/breandan/kotlingrad) integration module. - - - [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression. - - [scalars-adapters](src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-kotlingrad:0.4.0-dev-1") -} -``` diff --git a/kmath-kotlingrad/build.gradle.kts b/kmath-kotlingrad/build.gradle.kts index 56e191360..576c073c3 100644 --- a/kmath-kotlingrad/build.gradle.kts +++ b/kmath-kotlingrad/build.gradle.kts @@ -1,36 +1,19 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + plugins { - id("space.kscience.gradle.jvm") + kotlin("jvm") + id("ru.mipt.npm.gradle.common") } -kotlin.sourceSets - .filter { it.name.contains("test", true) } - .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) - .forEach { it.optIn("space.kscience.kmath.UnstableKMathAPI") } - -description = "Kotlin∇ integration module" - dependencies { - api("ai.hypergraph:kaliningraph:0.1.9") - api("ai.hypergraph:kotlingrad:0.4.7") - api(project(":kmath-core")) - testImplementation(project(":kmath-ast")) + implementation("com.github.breandan:kaliningraph:0.1.4") + implementation("com.github.breandan:kotlingrad:0.4.0") + api(project(":kmath-ast")) } readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature( - "differentiable-mst-expression", - "src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt", - ) { - "MST based DifferentiableExpression." - } - - feature( - "scalars-adapters", - "src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt", - ) { - "Conversions between Kotlin∇'s SFun and MST" - } -} + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE +} \ No newline at end of file diff --git a/kmath-kotlingrad/docs/README-TEMPLATE.md b/kmath-kotlingrad/docs/README-TEMPLATE.md deleted file mode 100644 index bc99bdf5f..000000000 --- a/kmath-kotlingrad/docs/README-TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -# Module kmath-kotlingrad - -[Kotlin∇](https://github.com/breandan/kotlingrad) integration module. - -${features} - -${artifact} diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt new file mode 100644 index 000000000..222145d2d --- /dev/null +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.kotlingrad + +import edu.umontreal.kotlingrad.api.SFun +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.MstAlgebra +import space.kscience.kmath.expressions.interpret +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.operations.NumericAlgebra + +/** + * Represents wrapper of [MstExpression] implementing [DifferentiableExpression]. + * + * The principle of this API is converting the [mst] to an [SFun], differentiating it with Kotlin∇, then converting + * [SFun] back to [MST]. + * + * @param T the type of number. + * @param A the [NumericAlgebra] of [T]. + * @property expr the underlying [MstExpression]. + */ +public class DifferentiableMstExpression>( + public val algebra: A, + public val mst: MST, +) : DifferentiableExpression> { + + public override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) + + public override fun derivativeOrNull(symbols: List): DifferentiableMstExpression = + DifferentiableMstExpression( + algebra, + symbols.map(Symbol::identity) + .map(MstAlgebra::bindSymbol) + .map { it.toSVar>() } + .fold(mst.toSFun(), SFun>::d) + .toMst(), + ) +} + +/** + * Wraps this [MST] into [DifferentiableMstExpression]. + */ +public fun > MST.toDiffExpression(algebra: A): DifferentiableMstExpression = + DifferentiableMstExpression(algebra, this) diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt index cd35e0c42..0c3768dcc 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt @@ -1,30 +1,23 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.kotlingrad -import ai.hypergraph.kotlingrad.api.SConst +import edu.umontreal.kotlingrad.api.RealNumber +import edu.umontreal.kotlingrad.api.SConst import space.kscience.kmath.operations.NumericAlgebra /** - * Implements [SConst] by delegating its functionality to [NumericAlgebra]. + * Implements [RealNumber] by delegating its functionality to [NumericAlgebra]. * - * @param T The type of number. - * @param A The [NumericAlgebra] over [T]. - * @property algebra The algebra. - * @property value The value of this number. + * @param T the type of number. + * @param A the [NumericAlgebra] of [T]. + * @property algebra the algebra. + * @param value the value of this number. */ -public class KMathNumber(public val algebra: A, override val value: T) : - SConst>(value) where T : Number, A : NumericAlgebra { - /** - * Returns a string representation of the [value]. - */ - override fun toString(): String = value.toString() - - /** - * Wraps [Number] to [KMathNumber]. - */ - override fun wrap(number: Number): KMathNumber = KMathNumber(algebra, algebra.number(number)) +public class KMathNumber(public val algebra: A, value: T) : + RealNumber, T>(value) where T : Number, A : NumericAlgebra { + public override fun wrap(number: Number): SConst> = SConst(algebra.number(number)) } diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt deleted file mode 100644 index 110572140..000000000 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.kotlingrad - -import ai.hypergraph.kotlingrad.api.SFun -import ai.hypergraph.kotlingrad.api.SVar -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.NumericAlgebra - -/** - * Represents [MST] based [DifferentiableExpression] relying on [Kotlin∇](https://github.com/breandan/kotlingrad). - * - * The principle of this API is converting the [mst] to an [SFun], differentiating it with Kotlin∇, then converting - * [SFun] back to [MST]. - * - * @param T The type of number. - * @param A The [NumericAlgebra] of [T]. - * @property algebra The [A] instance. - * @property mst The [MST] node. - */ -public class KotlingradExpression>( - public val algebra: A, - public val mst: MST, -) : SpecialDifferentiableExpression> { - override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) - - override fun derivativeOrNull( - symbols: List, - ): KotlingradExpression = KotlingradExpression( - algebra, - symbols.map(Symbol::identity) - .map(MstNumericAlgebra::bindSymbol) - .map>>(Symbol::toSVar) - .fold(mst.toSFun(), SFun>::d) - .toMst(), - ) -} - -/** - * A diff processor using [MST] to Kotlingrad converter - */ -public class KotlingradProcessor>( - public val algebra: A, -) : AutoDiffProcessor { - override fun differentiate(function: MstExtendedField.() -> MST): DifferentiableExpression = - MstExtendedField.function().toKotlingradExpression(algebra) -} - -/** - * Wraps this [MST] into [KotlingradExpression] in the context of [algebra]. - */ -public fun > MST.toKotlingradExpression(algebra: A): KotlingradExpression = - KotlingradExpression(algebra, this) diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/ScalarsAdapters.kt similarity index 63% rename from kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt rename to kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/ScalarsAdapters.kt index dd75a704c..f65d2948d 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/ScalarsAdapters.kt @@ -1,33 +1,32 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.kotlingrad -import ai.hypergraph.kotlingrad.api.* +import edu.umontreal.kotlingrad.api.* import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.MstAlgebra import space.kscience.kmath.expressions.MstExtendedField import space.kscience.kmath.expressions.MstExtendedField.unaryMinus -import space.kscience.kmath.expressions.MstNumericAlgebra -import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.* /** - * Maps [SVar] to [Symbol] directly. + * Maps [SVar] to [MST.Symbolic] directly. * - * @receiver The variable. - * @returnAa node. + * @receiver the variable. + * @return a node. */ -public fun > SVar.toMst(): Symbol = MstNumericAlgebra.bindSymbol(name) +public fun > SVar.toMst(): MST.Symbolic = MstAlgebra.bindSymbol(name) /** * Maps [SVar] to [MST.Numeric] directly. * - * @receiver The constant. - * @return A node. + * @receiver the constant. + * @return a node. */ -public fun > SConst.toMst(): MST.Numeric = MstNumericAlgebra.number(doubleValue) +public fun > SConst.toMst(): MST.Numeric = MstAlgebra.number(doubleValue) /** * Maps [SFun] objects to [MST]. Some unsupported operations like [Derivative] are bound and converted then. @@ -50,8 +49,8 @@ public fun > SConst.toMst(): MST.Numeric = MstNumericAlgebra.numb * - [VSumAll] is requested to be evaluated; * - [Derivative] is requested to be evaluated. * - * @receiver The scalar function. - * @return A node. + * @receiver the scalar function. + * @return a node. */ public fun > SFun.toMst(): MST = MstExtendedField { when (this@toMst) { @@ -75,18 +74,19 @@ public fun > SFun.toMst(): MST = MstExtendedField { /** * Maps [MST.Numeric] to [SConst] directly. * - * @receiver The node. - * @return A new constant. + * @receiver the node. + * @return a new constant. */ public fun > MST.Numeric.toSConst(): SConst = SConst(value) /** - * Maps [Symbol] to [SVar] directly. + * Maps [MST.Symbolic] to [SVar] directly. * - * @receiver The node. - * @return A new variable. + * @receiver the node. + * @param proto the prototype instance. + * @return a new variable. */ -internal fun > Symbol.toSVar(): SVar = SVar(identity) +internal fun > MST.Symbolic.toSVar(): SVar = SVar(value) /** * Maps [MST] objects to [SFun]. Unsupported operations throw [IllegalStateException]. @@ -94,40 +94,35 @@ internal fun > Symbol.toSVar(): SVar = SVar(identity) * Detailed mapping is: * * - [MST.Numeric] -> [SConst]; - * - [Symbol] -> [SVar]; + * - [MST.Symbolic] -> [SVar]; * - [MST.Unary] -> [Negative], [Sine], [Cosine], [Tangent], [Power], [Log]; * - [MST.Binary] -> [Sum], [Prod], [Power]. * - * @receiver The node. - * @return A scalar function. + * @receiver the node. + * @param proto the prototype instance. + * @return a scalar function. */ public fun > MST.toSFun(): SFun = when (this) { is MST.Numeric -> toSConst() - is Symbol -> toSVar() + is MST.Symbolic -> toSVar() is MST.Unary -> when (operation) { - GroupOps.PLUS_OPERATION -> +value.toSFun() - GroupOps.MINUS_OPERATION -> -value.toSFun() + GroupOperations.PLUS_OPERATION -> +value.toSFun() + GroupOperations.MINUS_OPERATION -> -value.toSFun() TrigonometricOperations.SIN_OPERATION -> sin(value.toSFun()) TrigonometricOperations.COS_OPERATION -> cos(value.toSFun()) TrigonometricOperations.TAN_OPERATION -> tan(value.toSFun()) PowerOperations.SQRT_OPERATION -> sqrt(value.toSFun()) ExponentialOperations.EXP_OPERATION -> exp(value.toSFun()) ExponentialOperations.LN_OPERATION -> value.toSFun().ln() - ExponentialOperations.SINH_OPERATION -> MstExtendedField { (exp(value) - exp(-value)) / 2.0 }.toSFun() - ExponentialOperations.COSH_OPERATION -> MstExtendedField { (exp(value) + exp(-value)) / 2.0 }.toSFun() - ExponentialOperations.TANH_OPERATION -> MstExtendedField { (exp(value) - exp(-value)) / (exp(-value) + exp(value)) }.toSFun() - ExponentialOperations.ASINH_OPERATION -> MstExtendedField { ln(sqrt(value * value + one) + value) }.toSFun() - ExponentialOperations.ACOSH_OPERATION -> MstExtendedField { ln(value + sqrt((value - one) * (value + one))) }.toSFun() - ExponentialOperations.ATANH_OPERATION -> MstExtendedField { (ln(value + one) - ln(one - value)) / 2.0 }.toSFun() else -> error("Unary operation $operation not defined in $this") } is MST.Binary -> when (operation) { - GroupOps.PLUS_OPERATION -> left.toSFun() + right.toSFun() - GroupOps.MINUS_OPERATION -> left.toSFun() - right.toSFun() - RingOps.TIMES_OPERATION -> left.toSFun() * right.toSFun() - FieldOps.DIV_OPERATION -> left.toSFun() / right.toSFun() + GroupOperations.PLUS_OPERATION -> left.toSFun() + right.toSFun() + GroupOperations.MINUS_OPERATION -> left.toSFun() - right.toSFun() + RingOperations.TIMES_OPERATION -> left.toSFun() * right.toSFun() + FieldOperations.DIV_OPERATION -> left.toSFun() / right.toSFun() PowerOperations.POW_OPERATION -> left.toSFun() pow (right as MST.Numeric).toSConst() else -> error("Binary operation $operation not defined in $this") } diff --git a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt index ccd89f063..66018a227 100644 --- a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt +++ b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt @@ -1,16 +1,14 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.kotlingrad -import ai.hypergraph.kotlingrad.api.* -import space.kscience.kmath.UnstableKMathAPI +import edu.umontreal.kotlingrad.api.* import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.ast.parseMath -import space.kscience.kmath.expressions.MstNumericAlgebra -import space.kscience.kmath.expressions.Symbol.Companion.x +import space.kscience.kmath.expressions.MstAlgebra import space.kscience.kmath.expressions.invoke import space.kscience.kmath.operations.DoubleField import kotlin.test.Test @@ -18,52 +16,52 @@ import kotlin.test.assertEquals import kotlin.test.assertTrue import kotlin.test.fail -@OptIn(UnstableKMathAPI::class) internal class AdaptingTests { @Test fun symbol() { - assertEquals(x.identity, x.toSVar>().name) + val c1 = MstAlgebra.bindSymbol("x") + assertTrue(c1.toSVar>().name == "x") val c2 = "kitten".parseMath().toSFun>() - if (c2 is SVar<*>) assertTrue(c2.name == "kitten") else fail() + if (c2 is SVar) assertTrue(c2.name == "kitten") else fail() } @Test fun number() { - val c1 = MstNumericAlgebra.number(12354324) + val c1 = MstAlgebra.number(12354324) assertTrue(c1.toSConst().doubleValue == 12354324.0) val c2 = "0.234".parseMath().toSFun>() - if (c2 is SConst<*>) assertTrue(c2.doubleValue == 0.234) else fail() + if (c2 is SConst) assertTrue(c2.doubleValue == 0.234) else fail() val c3 = "1e-3".parseMath().toSFun>() - if (c3 is SConst<*>) assertEquals(0.001, c3.value) else fail() + if (c3 is SConst) assertEquals(0.001, c3.value) else fail() } @Test fun simpleFunctionShape() { val linear = "2*x+16".parseMath().toSFun>() - if (linear !is Sum<*>) fail() - if (linear.left !is Prod<*>) fail() - if (linear.right !is SConst<*>) fail() + if (linear !is Sum) fail() + if (linear.left !is Prod) fail() + if (linear.right !is SConst) fail() } @Test fun simpleFunctionDerivative() { - val xSVar = x.toSVar>() + val x = MstAlgebra.bindSymbol("x").toSVar>() val quadratic = "x^2-4*x-44".parseMath().toSFun>() - val actualDerivative = quadratic.d(xSVar).toMst().compileToExpression(DoubleField) + val actualDerivative = quadratic.d(x).toMst().compileToExpression(DoubleField) val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField) - assertEquals(actualDerivative(x to 123.0), expectedDerivative(x to 123.0)) + assertEquals(actualDerivative("x" to 123.0), expectedDerivative("x" to 123.0)) } @Test fun moreComplexDerivative() { - val xSVar = x.toSVar>() + val x = MstAlgebra.bindSymbol("x").toSVar>() val composition = "-sqrt(sin(x^2)-cos(x)^2-16*x)".parseMath().toSFun>() - val actualDerivative = composition.d(xSVar).toMst().compileToExpression(DoubleField) + val actualDerivative = composition.d(x).toMst().compileToExpression(DoubleField) - val expectedDerivative = "-(2*x*cos(x^2)+2*sin(x)*cos(x)-16)/(2*sqrt(sin(x^2)-16*x-cos(x)^2))" - .parseMath() - .compileToExpression(DoubleField) + val expectedDerivative = + "-(2*x*cos(x^2)+2*sin(x)*cos(x)-16)/(2*sqrt(sin(x^2)-16*x-cos(x)^2))".parseMath().compileToExpression(DoubleField) - assertEquals(actualDerivative(x to -0.1), expectedDerivative(x to -0.1)) + + assertEquals(actualDerivative("x" to 0.1), expectedDerivative("x" to 0.1)) } } diff --git a/kmath-memory/README.md b/kmath-memory/README.md deleted file mode 100644 index 594588ecf..000000000 --- a/kmath-memory/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-memory - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-memory:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-memory:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-memory:0.4.0-dev-1") -} -``` diff --git a/kmath-memory/api/kmath-memory.api b/kmath-memory/api/kmath-memory.api index cebb04af2..9c9641461 100644 --- a/kmath-memory/api/kmath-memory.api +++ b/kmath-memory/api/kmath-memory.api @@ -1,14 +1,3 @@ -public abstract interface annotation class space/kscience/kmath/PerformancePitfall : java/lang/annotation/Annotation { - public abstract fun message ()Ljava/lang/String; -} - -public abstract interface annotation class space/kscience/kmath/UnsafeKMathAPI : java/lang/annotation/Annotation { - public abstract fun message ()Ljava/lang/String; -} - -public abstract interface annotation class space/kscience/kmath/UnstableKMathAPI : java/lang/annotation/Annotation { -} - public final class space/kscience/kmath/memory/ByteBufferMemory : space/kscience/kmath/memory/Memory { public fun (Ljava/nio/ByteBuffer;II)V public synthetic fun (Ljava/nio/ByteBuffer;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -47,8 +36,7 @@ public final class space/kscience/kmath/memory/MemoryKt { public static final fun write (Lspace/kscience/kmath/memory/Memory;Lkotlin/jvm/functions/Function1;)V } -public abstract interface class space/kscience/kmath/memory/MemoryReader : java/lang/AutoCloseable { - public abstract fun close ()V +public abstract interface class space/kscience/kmath/memory/MemoryReader { public abstract fun getMemory ()Lspace/kscience/kmath/memory/Memory; public abstract fun readByte (I)B public abstract fun readDouble (I)D @@ -56,6 +44,7 @@ public abstract interface class space/kscience/kmath/memory/MemoryReader : java/ public abstract fun readInt (I)I public abstract fun readLong (I)J public abstract fun readShort (I)S + public abstract fun release ()V } public abstract interface class space/kscience/kmath/memory/MemorySpec { @@ -70,9 +59,9 @@ public final class space/kscience/kmath/memory/MemorySpecKt { public static final fun writeArray (Lspace/kscience/kmath/memory/MemoryWriter;Lspace/kscience/kmath/memory/MemorySpec;I[Ljava/lang/Object;)V } -public abstract interface class space/kscience/kmath/memory/MemoryWriter : java/lang/AutoCloseable { - public abstract fun close ()V +public abstract interface class space/kscience/kmath/memory/MemoryWriter { public abstract fun getMemory ()Lspace/kscience/kmath/memory/Memory; + public abstract fun release ()V public abstract fun writeByte (IB)V public abstract fun writeDouble (ID)V public abstract fun writeFloat (IF)V diff --git a/kmath-memory/build.gradle.kts b/kmath-memory/build.gradle.kts index 8c1e63cb7..50c317324 100644 --- a/kmath-memory/build.gradle.kts +++ b/kmath-memory/build.gradle.kts @@ -1,32 +1,17 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + plugins { - id("space.kscience.gradle.mpp") -} - -kscience { - jvm() - js() - native() - wasm{ - browser { - testTask { - useKarma { - webpackConfig.experiments.add("topLevelAwait") - useChromeHeadless() - } - } - } - } - - wasmTest{ - dependencies { - implementation(kotlin("test")) - } - } + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } readme { - maturity = space.kscience.gradle.Maturity.DEVELOPMENT + maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT description = """ - An API and basic implementation for arranging objects in a continuous memory block. + An API and basic implementation for arranging objects in a continous memory block. """.trimIndent() -} +} \ No newline at end of file diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/annotations.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/annotations.kt deleted file mode 100644 index a95b166cf..000000000 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/annotations.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath - -/** - * Marks declarations that are still experimental in the KMath APIs, which means that the design of the corresponding - * declarations has open issues that may (or may not) lead to their changes in the future. Roughly speaking, there is - * a chance of those declarations will be deprecated in the near future or the semantics of their behavior may change - * in some way that may break some code. - */ -@MustBeDocumented -@Retention(value = AnnotationRetention.BINARY) -@RequiresOptIn("This API is unstable and could change in future", RequiresOptIn.Level.WARNING) -public annotation class UnstableKMathAPI - -/** - * Marks API that could cause performance problems. The code marked by this API is unnecessary slow but could cause - * slow-down in some cases. Refer to the documentation and benchmark it to be sure. - */ -@MustBeDocumented -@Retention(value = AnnotationRetention.BINARY) -@RequiresOptIn( - "Refer to the documentation to use this API in performance-critical code", - RequiresOptIn.Level.WARNING, -) -public annotation class PerformancePitfall( - val message: String = "Potential performance problem", -) - -/** - * Marks API that is public, but should not be used without clear understanding what it does. - */ -@MustBeDocumented -@Retention(value = AnnotationRetention.BINARY) -@RequiresOptIn( - "This API is unsafe and should be used carefully", - RequiresOptIn.Level.ERROR, -) -public annotation class UnsafeKMathAPI( - val message: String = "Unsafe API", -) diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt index a63753015..930b21095 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -43,7 +43,7 @@ public interface Memory { /** * The interface to read primitive types in this memory. */ -public interface MemoryReader: AutoCloseable { +public interface MemoryReader { /** * The underlying memory. */ @@ -82,7 +82,7 @@ public interface MemoryReader: AutoCloseable { /** * Disposes this reader if needed. */ - override fun close() + public fun release() } /** @@ -90,13 +90,16 @@ public interface MemoryReader: AutoCloseable { */ public inline fun Memory.read(block: MemoryReader.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return reader().use(block) + val reader = reader() + val result = reader.block() + reader.release() + return result } /** * The interface to write primitive types into this memory. */ -public interface MemoryWriter: AutoCloseable { +public interface MemoryWriter { /** * The underlying memory. */ @@ -135,7 +138,7 @@ public interface MemoryWriter: AutoCloseable { /** * Disposes this writer if needed. */ - override fun close() + public fun release() } /** @@ -143,7 +146,7 @@ public interface MemoryWriter: AutoCloseable { */ public inline fun Memory.write(block: MemoryWriter.() -> Unit) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - writer().use(block) + writer().apply(block).release() } /** @@ -153,6 +156,6 @@ public expect fun Memory.Companion.allocate(length: Int): Memory /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently of the resulting [Memory]. + * and could be mutated independently from the resulting [Memory]. */ public expect fun Memory.Companion.wrap(array: ByteArray): Memory diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt index 19bc3bae4..1ee1cf4e2 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt b/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt deleted file mode 100644 index 3726ddbb7..000000000 --- a/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.memory - -import kotlin.test.Test -import kotlin.test.assertEquals - -class MemoryTest { - @Test - fun memoryWriteRead() { - val memorySize = 60 - val data = buildList { - for (i in 0 until (memorySize / 4)) { - add(i) - } - } - val memory = Memory.allocate(memorySize) - memory.write { - for (i in 0 until (memory.size / 4)) { - writeInt(i*4, data[i]) - } - } - - val result = memory.read { - buildList { - for (i in 0 until (memory.size / 4)) { - add(readInt(i*4)) - } - } - } - - assertEquals(data,result) - } -} \ No newline at end of file diff --git a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt index f8bcef010..9a622ea36 100644 --- a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt +++ b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -41,7 +41,7 @@ private class DataViewMemory(val view: DataView) : Memory { override fun readLong(offset: Int): Long = view.getInt32(offset, false).toLong() shl 32 or view.getInt32(offset + 4, false).toLong() - override fun close() { + override fun release() { // does nothing on JS } } @@ -76,7 +76,7 @@ private class DataViewMemory(val view: DataView) : Memory { view.setInt32(offset + 4, (value and 0xffffffffL).toInt(), littleEndian = false) } - override fun close() { + override fun release() { // does nothing on JS } } @@ -95,7 +95,7 @@ public actual fun Memory.Companion.allocate(length: Int): Memory { /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently of the resulting [Memory]. + * and could be mutated independently from the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory { @Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array diff --git a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt index d022cab23..944e8455b 100644 --- a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt +++ b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -20,7 +20,8 @@ internal class ByteBufferMemory( val startOffset: Int = 0, override val size: Int = buffer.limit(), ) : Memory { - private fun position(offset: Int): Int = startOffset + offset + @Suppress("NOTHING_TO_INLINE") + private inline fun position(o: Int): Int = startOffset + o override fun view(offset: Int, length: Int): Memory { require(offset >= 0) { "offset shouldn't be negative: $offset" } @@ -52,7 +53,7 @@ internal class ByteBufferMemory( override fun readLong(offset: Int) = buffer.getLong(position(offset)) - override fun close() { + override fun release() { // does nothing on JVM } } @@ -86,7 +87,7 @@ internal class ByteBufferMemory( buffer.putLong(position(offset), value) } - override fun close() { + override fun release() { // does nothing on JVM } } @@ -102,7 +103,7 @@ public actual fun Memory.Companion.allocate(length: Int): Memory = /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently of the resulting [Memory]. + * and could be mutated independently from the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory = ByteBufferMemory(checkNotNull(ByteBuffer.wrap(array))) @@ -119,7 +120,7 @@ public fun ByteBuffer.asMemory(startOffset: Int = 0, size: Int = limit()): Memor ByteBufferMemory(this, startOffset, size) /** - * Uses direct memory-mapped buffer from file to read something and close it afterward. + * Uses direct memory-mapped buffer from file to read something and close it afterwards. */ @Throws(IOException::class) public inline fun Path.readAsMemory(position: Long = 0, size: Long = Files.size(this), block: Memory.() -> R): R { diff --git a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt index 32bc8d6a5..d31c9e8f4 100644 --- a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt +++ b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -41,7 +41,7 @@ internal class NativeMemory( override fun readLong(offset: Int) = array.getLongAt(position(offset)) - override fun close() { + override fun release() { // does nothing on JVM } } @@ -60,7 +60,7 @@ internal class NativeMemory( } override fun writeByte(offset: Int, value: Byte) { - array[position(offset)] = value + array.set(position(offset), value) } override fun writeShort(offset: Int, value: Short) { @@ -75,7 +75,7 @@ internal class NativeMemory( array.setLongAt(position(offset), value) } - override fun close() { + override fun release() { // does nothing on JVM } } @@ -85,7 +85,7 @@ internal class NativeMemory( /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently of the resulting [Memory]. + * and could be mutated independently from the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory = NativeMemory(array) diff --git a/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt b/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt deleted file mode 100644 index 0cff551fa..000000000 --- a/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.memory - -import org.khronos.webgl.ArrayBuffer -import org.khronos.webgl.DataView -import org.khronos.webgl.Int8Array - -private class WasmDataViewMemory(val view: DataView) : Memory { - override val size: Int get() = view.byteLength - - override fun view(offset: Int, length: Int): Memory { - require(offset >= 0) { "offset shouldn't be negative: $offset" } - require(length >= 0) { "length shouldn't be negative: $length" } - require(offset + length <= size) { "Can't view memory outside the parent region." } - - if (offset + length > size) - throw IndexOutOfBoundsException("offset + length > size: $offset + $length > $size") - - return WasmDataViewMemory(DataView(view.buffer, view.byteOffset + offset, length)) - } - - override fun copy(): Memory = WasmDataViewMemory(DataView(view.buffer.slice(0))) - - private val reader: MemoryReader = object : MemoryReader { - override val memory: Memory get() = this@WasmDataViewMemory - - override fun readDouble(offset: Int): Double = view.getFloat64(offset, false) - - override fun readFloat(offset: Int): Float = view.getFloat32(offset, false) - - override fun readByte(offset: Int): Byte = view.getInt8(offset) - - override fun readShort(offset: Int): Short = view.getInt16(offset, false) - - override fun readInt(offset: Int): Int = view.getInt32(offset, false) - - override fun readLong(offset: Int): Long = - view.getInt32(offset, false).toLong() shl 32 or view.getInt32(offset + 4, false).toLong() - - override fun close() { - // does nothing on JS - } - } - - override fun reader(): MemoryReader = reader - - private val writer: MemoryWriter = object : MemoryWriter { - override val memory: Memory get() = this@WasmDataViewMemory - - override fun writeDouble(offset: Int, value: Double) { - view.setFloat64(offset, value, false) - } - - override fun writeFloat(offset: Int, value: Float) { - view.setFloat32(offset, value, false) - } - - override fun writeByte(offset: Int, value: Byte) { - view.setInt8(offset, value) - } - - override fun writeShort(offset: Int, value: Short) { - view.setUint16(offset, value, false) - } - - override fun writeInt(offset: Int, value: Int) { - view.setInt32(offset, value, false) - } - - override fun writeLong(offset: Int, value: Long) { - view.setInt32(offset, (value shr 32).toInt(), littleEndian = false) - view.setInt32(offset + 4, (value and 0xffffffffL).toInt(), littleEndian = false) - } - - override fun close() { - // does nothing on JS - } - } - - override fun writer(): MemoryWriter = writer - -} - -/** - * Allocates memory based on a [DataView]. - */ -public actual fun Memory.Companion.allocate(length: Int): Memory { - val buffer = ArrayBuffer(length) - return WasmDataViewMemory(DataView(buffer, 0, length)) -} - -/** - * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently of the resulting [Memory]. - */ -public actual fun Memory.Companion.wrap(array: ByteArray): Memory { - @Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array - return WasmDataViewMemory(DataView(int8Array.buffer, int8Array.byteOffset, int8Array.length)) -} diff --git a/kmath-multik/README.md b/kmath-multik/README.md deleted file mode 100644 index 127b12a49..000000000 --- a/kmath-multik/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-multik - -JetBrains Multik connector - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-multik:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-multik:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-multik:0.4.0-dev-1") -} -``` diff --git a/kmath-multik/build.gradle.kts b/kmath-multik/build.gradle.kts deleted file mode 100644 index fc51d2c21..000000000 --- a/kmath-multik/build.gradle.kts +++ /dev/null @@ -1,32 +0,0 @@ -plugins { - id("space.kscience.gradle.mpp") -} - -description = "JetBrains Multik connector" - -val multikVersion: String by rootProject.extra - -kscience { - jvm() - js() -} - -kotlin{ - sourceSets{ - commonMain{ - dependencies{ - api(project(":kmath-tensors")) - api("org.jetbrains.kotlinx:multik-core:$multikVersion") - } - } - commonTest{ - dependencies{ - api("org.jetbrains.kotlinx:multik-default:$multikVersion") - } - } - } -} - -readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE -} \ No newline at end of file diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt deleted file mode 100644 index beab5c18b..000000000 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.api.Engine -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.ndarrayOf -import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExponentialOperations -import space.kscience.kmath.operations.TrigonometricOperations - -public class MultikDoubleAlgebra( - multikEngine: Engine -) : MultikDivisionTensorAlgebra(multikEngine), - TrigonometricOperations>, ExponentialOperations> { - override val elementAlgebra: DoubleField get() = DoubleField - override val type: DataType get() = DataType.DoubleDataType - - override fun sin(arg: StructureND): MultikTensor = multikMath.mathEx.sin(arg.asMultik().array).wrap() - - override fun cos(arg: StructureND): MultikTensor = multikMath.mathEx.cos(arg.asMultik().array).wrap() - - override fun tan(arg: StructureND): MultikTensor = sin(arg) / cos(arg) - - @PerformancePitfall - override fun asin(arg: StructureND): MultikTensor = arg.map { asin(it) } - - @PerformancePitfall - override fun acos(arg: StructureND): MultikTensor = arg.map { acos(it) } - - @PerformancePitfall - override fun atan(arg: StructureND): MultikTensor = arg.map { atan(it) } - - override fun exp(arg: StructureND): MultikTensor = multikMath.mathEx.exp(arg.asMultik().array).wrap() - - override fun ln(arg: StructureND): MultikTensor = multikMath.mathEx.log(arg.asMultik().array).wrap() - - override fun sinh(arg: StructureND): MultikTensor = (exp(arg) - exp(-arg)) / 2.0 - - override fun cosh(arg: StructureND): MultikTensor = (exp(arg) + exp(-arg)) / 2.0 - - override fun tanh(arg: StructureND): MultikTensor { - val expPlus = exp(arg) - val expMinus = exp(-arg) - return (expPlus - expMinus) / (expPlus + expMinus) - } - - @PerformancePitfall - override fun asinh(arg: StructureND): MultikTensor = arg.map { asinh(it) } - - @PerformancePitfall - override fun acosh(arg: StructureND): MultikTensor = arg.map { acosh(it) } - - @PerformancePitfall - override fun atanh(arg: StructureND): MultikTensor = arg.map { atanh(it) } - - override fun scalar(value: Double): MultikTensor = Multik.ndarrayOf(value).wrap() -} - -//public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra -//public val DoubleField.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra - diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt deleted file mode 100644 index ee194ae24..000000000 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.api.Engine -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.ndarrayOf -import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.operations.FloatField - -public class MultikFloatAlgebra( - multikEngine: Engine -) : MultikDivisionTensorAlgebra(multikEngine) { - override val elementAlgebra: FloatField get() = FloatField - override val type: DataType get() = DataType.FloatDataType - - override fun scalar(value: Float): MultikTensor = Multik.ndarrayOf(value).wrap() -} - - -//public val Float.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra -//public val FloatField.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra \ No newline at end of file diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt deleted file mode 100644 index 05b240787..000000000 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.api.Engine -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.ndarrayOf -import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.operations.IntRing - -public class MultikIntAlgebra( - multikEngine: Engine -) : MultikTensorAlgebra(multikEngine) { - override val elementAlgebra: IntRing get() = IntRing - override val type: DataType get() = DataType.IntDataType - override fun scalar(value: Int): MultikTensor = Multik.ndarrayOf(value).wrap() -} - -//public val Int.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra -//public val IntRing.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra \ No newline at end of file diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt deleted file mode 100644 index e713e556e..000000000 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.api.Engine -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.ndarrayOf -import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.operations.LongRing - -public class MultikLongAlgebra( - multikEngine: Engine -) : MultikTensorAlgebra(multikEngine) { - override val elementAlgebra: LongRing get() = LongRing - override val type: DataType get() = DataType.LongDataType - - override fun scalar(value: Long): MultikTensor = Multik.ndarrayOf(value).wrap() -} - - -//public val Long.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra -//public val LongRing.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra \ No newline at end of file diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt deleted file mode 100644 index 6e5ca5882..000000000 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.api.Engine -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.ndarrayOf -import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.operations.ShortRing - -public class MultikShortAlgebra( - multikEngine: Engine -) : MultikTensorAlgebra(multikEngine) { - override val elementAlgebra: ShortRing get() = ShortRing - override val type: DataType get() = DataType.ShortDataType - override fun scalar(value: Short): MultikTensor = Multik.ndarrayOf(value).wrap() -} - -//public val Short.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra -//public val ShortRing.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra \ No newline at end of file diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt deleted file mode 100644 index 59a9a1bf3..000000000 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.ndarray.data.* -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.tensors.api.Tensor -import kotlin.jvm.JvmInline - -@JvmInline -public value class MultikTensor(public val array: MutableMultiArray) : Tensor { - override val shape: ShapeND get() = ShapeND(array.shape) - - @PerformancePitfall - override fun get(index: IntArray): T = array[index] - - @PerformancePitfall - override fun elements(): Sequence> = - array.multiIndices.iterator().asSequence().map { it to get(it) } - - @PerformancePitfall - override fun set(index: IntArray, value: T) { - array[index] = value - } -} - - -internal fun MultiArray.asD1Array(): D1Array { - if (this is NDArray) - return this.asD1Array() - else throw ClassCastException("Cannot cast MultiArray to NDArray.") -} - - -internal fun MultiArray.asD2Array(): D2Array { - if (this is NDArray) - return this.asD2Array() - else throw ClassCastException("Cannot cast MultiArray to NDArray.") -} \ No newline at end of file diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt deleted file mode 100644 index c3a82b167..000000000 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("unused") - -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.api.* -import org.jetbrains.kotlinx.multik.api.linalg.LinAlg -import org.jetbrains.kotlinx.multik.api.math.Math -import org.jetbrains.kotlinx.multik.api.stat.Statistics -import org.jetbrains.kotlinx.multik.ndarray.data.* -import org.jetbrains.kotlinx.multik.ndarray.operations.* -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnsafeKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.api.TensorAlgebra -import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra - -public abstract class MultikTensorAlgebra>( - private val multikEngine: Engine, -) : TensorAlgebra where T : Number, T : Comparable { - - public abstract val type: DataType - - protected val multikMath: Math = multikEngine.getMath() - protected val multikLinAl: LinAlg = multikEngine.getLinAlg() - protected val multikStat: Statistics = multikEngine.getStatistics() - - @OptIn(UnsafeKMathAPI::class) - override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): MultikTensor { - val strides = ColumnStrides(shape) - val memoryView = initMemoryView(strides.linearSize, type) - strides.asSequence().forEachIndexed { linearIndex, tensorIndex -> - memoryView[linearIndex] = elementAlgebra.initializer(tensorIndex) - } - return MultikTensor(NDArray(memoryView, shape = shape.asArray(), dim = DN(shape.size))) - } - - @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class) - override fun StructureND.map(transform: A.(T) -> T): MultikTensor = if (this is MultikTensor) { - val data = initMemoryView(array.size, type) - var count = 0 - for (el in array) data[count++] = elementAlgebra.transform(el) - NDArray(data, shape = shape.asArray(), dim = array.dim).wrap() - } else { - structureND(shape) { index -> - transform(get(index)) - } - } - - @OptIn(PerformancePitfall::class) - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): MultikTensor = - if (this is MultikTensor) { - val array = asMultik().array - val data = initMemoryView(array.size, type) - val indexIter = array.multiIndices.iterator() - var index = 0 - for (item in array) { - if (indexIter.hasNext()) { - data[index++] = elementAlgebra.transform(indexIter.next(), item) - } else { - throw ArithmeticException("Index overflow has happened.") - } - } - NDArray(data, shape = array.shape, dim = array.dim).wrap() - } else { - structureND(shape) { index -> - transform(index, get(index)) - } - } - - /** - * Transform a structure element-by element in place. - */ - @OptIn(PerformancePitfall::class) - public inline fun MutableStructureND.mapIndexedInPlace(operation: (index: IntArray, t: T) -> T): Unit { - if (this is MultikTensor) { - array.multiIndices.iterator().forEach { - set(it, operation(it, get(it))) - } - } else { - indices.forEach { set(it, operation(it, get(it))) } - } - } - - - @OptIn(PerformancePitfall::class) - override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): MultikTensor { - require(left.shape.contentEquals(right.shape)) { "ND array shape mismatch" } //TODO replace by ShapeMismatchException - val leftArray = left.asMultik().array - val rightArray = right.asMultik().array - val data = initMemoryView(leftArray.size, type) - var counter = 0 - val leftIterator = leftArray.iterator() - val rightIterator = rightArray.iterator() - //iterating them together - while (leftIterator.hasNext()) { - data[counter++] = elementAlgebra.transform(leftIterator.next(), rightIterator.next()) - } - return NDArray(data, shape = leftArray.shape, dim = leftArray.dim).wrap() - } - - /** - * Convert a tensor to [MultikTensor] if necessary. If tensor is converted, changes on the resulting tensor - * are not reflected back onto the source - */ - @OptIn(UnsafeKMathAPI::class, PerformancePitfall::class) - public fun StructureND.asMultik(): MultikTensor = if (this is MultikTensor) { - this - } else { - val res = mk.zeros(shape.asArray(), type).asDNArray() - for (index in res.multiIndices) { - res[index] = this[index] - } - res.wrap() - } - - public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this.asDNArray()) - - @OptIn(PerformancePitfall::class) - override fun StructureND.valueOrNull(): T? = if (shape contentEquals ShapeND(1)) { - get(intArrayOf(0)) - } else null - - override fun T.plus(arg: StructureND): MultikTensor = - arg.plus(this) - - override fun StructureND.plus(arg: T): MultikTensor = - asMultik().array.deepCopy().apply { plusAssign(arg) }.wrap() - - override fun StructureND.plus(arg: StructureND): MultikTensor = - asMultik().array.plus(arg.asMultik().array).wrap() - - override fun Tensor.plusAssign(value: T) { - if (this is MultikTensor) { - array.plusAssign(value) - } else { - mapIndexedInPlace { _, t -> elementAlgebra.add(t, value) } - } - } - - @OptIn(PerformancePitfall::class) - override fun Tensor.plusAssign(arg: StructureND) { - if (this is MultikTensor) { - array.plusAssign(arg.asMultik().array) - } else { - mapIndexedInPlace { index, t -> elementAlgebra.add(t, arg[index]) } - } - } - - override fun T.minus(arg: StructureND): MultikTensor = (-(arg.asMultik().array - this)).wrap() - - override fun StructureND.minus(arg: T): MultikTensor = - asMultik().array.deepCopy().apply { minusAssign(arg) }.wrap() - - override fun StructureND.minus(arg: StructureND): MultikTensor = - asMultik().array.minus(arg.asMultik().array).wrap() - - override fun Tensor.minusAssign(value: T) { - if (this is MultikTensor) { - array.minusAssign(value) - } else { - mapIndexedInPlace { _, t -> elementAlgebra.run { t - value } } - } - } - - @OptIn(PerformancePitfall::class) - override fun Tensor.minusAssign(arg: StructureND) { - if (this is MultikTensor) { - array.minusAssign(arg.asMultik().array) - } else { - mapIndexedInPlace { index, t -> elementAlgebra.run { t - arg[index] } } - } - } - - override fun T.times(arg: StructureND): MultikTensor = - arg.asMultik().array.deepCopy().apply { timesAssign(this@times) }.wrap() - - override fun StructureND.times(arg: T): Tensor = - asMultik().array.deepCopy().apply { timesAssign(arg) }.wrap() - - override fun StructureND.times(arg: StructureND): MultikTensor = - asMultik().array.times(arg.asMultik().array).wrap() - - override fun Tensor.timesAssign(value: T) { - if (this is MultikTensor) { - array.timesAssign(value) - } else { - mapIndexedInPlace { _, t -> elementAlgebra.multiply(t, value) } - } - } - - @OptIn(PerformancePitfall::class) - override fun Tensor.timesAssign(arg: StructureND) { - if (this is MultikTensor) { - array.timesAssign(arg.asMultik().array) - } else { - mapIndexedInPlace { index, t -> elementAlgebra.multiply(t, arg[index]) } - } - } - - override fun StructureND.unaryMinus(): MultikTensor = - asMultik().array.unaryMinus().wrap() - - override fun Tensor.getTensor(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() - - override fun StructureND.transposed(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() - - override fun Tensor.view(shape: ShapeND): MultikTensor { - require(shape.asList().all { it > 0 }) - require(shape.linearSize == this.shape.size) { - "Cannot reshape array of size ${this.shape.size} into a new shape ${ - shape.asList().joinToString( - prefix = "(", - postfix = ")" - ) - }" - } - - val mt = asMultik().array - return if (ShapeND(mt.shape).contentEquals(shape)) { - mt - } else { - @OptIn(UnsafeKMathAPI::class) - NDArray(mt.data, mt.offset, shape.asArray(), dim = DN(shape.size), base = mt.base ?: mt) - }.wrap() - } - - override fun Tensor.viewAs(other: StructureND): MultikTensor = view(other.shape) - - public abstract fun scalar(value: T): MultikTensor - - override fun StructureND.dot(other: StructureND): MultikTensor = - if (this.shape.size == 1 && other.shape.size == 1) { - scalar( - multikLinAl.linAlgEx.dotVV( - asMultik().array.asD1Array(), other.asMultik().array.asD1Array() - ) - ) - } else if (this.shape.size == 2 && other.shape.size == 2) { - multikLinAl.linAlgEx.dotMM(asMultik().array.asD2Array(), other.asMultik().array.asD2Array()).wrap() - } else if (this.shape.size == 2 && other.shape.size == 1) { - multikLinAl.linAlgEx.dotMV(asMultik().array.asD2Array(), other.asMultik().array.asD1Array()).wrap() - } else { - TODO("Not implemented for broadcasting") - } - - override fun diagonalEmbedding(diagonalEntries: StructureND, offset: Int, dim1: Int, dim2: Int): MultikTensor { - - TODO("Diagonal embedding not implemented") - } - - override fun StructureND.sum(): T = multikMath.sum(asMultik().array) - - override fun StructureND.sum(dim: Int, keepDim: Boolean): MultikTensor { - if (keepDim) TODO("keepDim not implemented") - return multikMath.sumDN(asMultik().array, dim).wrap() - } - - override fun StructureND.min(): T? = asMultik().array.min() - - override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor { - if (keepDim) TODO("keepDim not implemented") - return multikMath.minDN(asMultik().array, dim).wrap() - } - - override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor { - if (keepDim) TODO("keepDim not implemented") - val res = multikMath.argMinDN(asMultik().array, dim) - return with(MultikIntAlgebra(multikEngine)) { res.wrap() } - } - - override fun StructureND.max(): T? = asMultik().array.max() - - override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor { - if (keepDim) TODO("keepDim not implemented") - return multikMath.maxDN(asMultik().array, dim).wrap() - } - - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { - if (keepDim) TODO("keepDim not implemented") - val res = multikMath.argMaxDN(asMultik().array, dim) - return with(MultikIntAlgebra(multikEngine)) { res.wrap() } - } -} - -public abstract class MultikDivisionTensorAlgebra>( - multikEngine: Engine, -) : MultikTensorAlgebra(multikEngine), TensorPartialDivisionAlgebra where T : Number, T : Comparable { - - @OptIn(UnsafeKMathAPI::class) - override fun T.div(arg: StructureND): MultikTensor = - Multik.ones(arg.shape.asArray(), type).apply { divAssign(arg.asMultik().array) }.wrap() - - override fun StructureND.div(arg: T): MultikTensor = - asMultik().array.div(arg).wrap() - - override fun StructureND.div(arg: StructureND): MultikTensor = - asMultik().array.div(arg.asMultik().array).wrap() - - override fun Tensor.divAssign(value: T) { - if (this is MultikTensor) { - array.divAssign(value) - } else { - mapIndexedInPlace { _, t -> elementAlgebra.divide(t, value) } - } - } - - @OptIn(PerformancePitfall::class) - override fun Tensor.divAssign(arg: StructureND) { - if (this is MultikTensor) { - array.divAssign(arg.asMultik().array) - } else { - mapIndexedInPlace { index, t -> elementAlgebra.divide(t, arg[index]) } - } - } -} \ No newline at end of file diff --git a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt deleted file mode 100644 index 1a130aa92..000000000 --- a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.default.DefaultEngine -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.one -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.randomNormal -import space.kscience.kmath.tensors.core.tensorAlgebra -import kotlin.test.Test -import kotlin.test.assertTrue - -@OptIn(PerformancePitfall::class) -internal class MultikNDTest { - val multikAlgebra = MultikDoubleAlgebra(DefaultEngine()) - - @Test - fun basicAlgebra(): Unit = with(multikAlgebra) { - one(2, 2) + 1.0 - } - - @Test - fun dotResult() { - val dim = 100 - - val tensor1 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12224) - val tensor2 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12225) - - val multikResult = with(multikAlgebra) { - tensor1 dot tensor2 - } - - val defaultResult = with(DoubleField.tensorAlgebra) { - tensor1 dot tensor2 - } - - assertTrue { - StructureND.contentEquals(multikResult, defaultResult) - } - - } -} \ No newline at end of file diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index b299c1b37..829fe4142 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,28 +9,30 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.4.0-dev-1`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-6`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } - mavenCentral() + maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap } dependencies { - implementation 'space.kscience:kmath-nd4j:0.4.0-dev-1' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-6' } ``` **Gradle Kotlin DSL:** ```kotlin repositories { maven("https://repo.kotlin.link") - mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap + maven("https://dl.bintray.com/hotkeytlt/maven") // required for a } dependencies { - implementation("space.kscience:kmath-nd4j:0.4.0-dev-1") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-6") } ``` diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts index e5c4af891..17232b44f 100644 --- a/kmath-nd4j/build.gradle.kts +++ b/kmath-nd4j/build.gradle.kts @@ -1,20 +1,40 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity + plugins { - id("space.kscience.gradle.jvm") + kotlin("jvm") + id("ru.mipt.npm.gradle.common") } -description = "ND4J NDStructure implementation and according NDAlgebra classes" - dependencies { - api(project(":kmath-tensors")) - api("org.nd4j:nd4j-api:1.0.0-M1") - testImplementation("org.nd4j:nd4j-native-platform:1.0.0-M1") - testImplementation("org.slf4j:slf4j-simple:1.7.32") + api(project(":kmath-core")) + api("org.nd4j:nd4j-api:1.0.0-beta7") + testImplementation("org.deeplearning4j:deeplearning4j-core:1.0.0-beta7") + testImplementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") + testImplementation("org.slf4j:slf4j-simple:1.7.30") } readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + description = "ND4J NDStructure implementation and according NDAlgebra classes" + maturity = Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - feature(id = "nd4jarraystructure") { "NDStructure wrapper for INDArray" } - feature(id = "nd4jarrayrings") { "Rings over Nd4jArrayStructure of Int and Long" } - feature(id = "nd4jarrayfields") { "Fields over Nd4jArrayStructure of Float and Double" } + + feature( + id = "nd4jarraystructure", + description = "NDStructure wrapper for INDArray" + ) + + feature( + id = "nd4jarrayrings", + description = "Rings over Nd4jArrayStructure of Int and Long" + ) + + feature( + id = "nd4jarrayfields", + description = "Fields over Nd4jArrayStructure of Float and Double" + ) } diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt index 0eb147b6f..f2c69adee 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt @@ -1,20 +1,23 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd4j import org.nd4j.linalg.api.ndarray.INDArray -import org.nd4j.linalg.api.ops.impl.transforms.strict.ACosh -import org.nd4j.linalg.api.ops.impl.transforms.strict.ASinh import org.nd4j.linalg.factory.Nd4j -import org.nd4j.linalg.ops.transforms.Transforms -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnsafeKMathAPI -import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.* + +internal fun AlgebraND<*, *>.checkShape(array: INDArray): INDArray { + val arrayShape = array.shape().toIntArray() + if (!shape.contentEquals(arrayShape)) throw ShapeMismatchException(shape, arrayShape) + return array +} + /** * Represents [AlgebraND] over [Nd4jArrayAlgebra]. @@ -22,50 +25,51 @@ import space.kscience.kmath.operations.* * @param T the type of ND-structure element. * @param C the type of the element context. */ -public sealed interface Nd4jArrayAlgebra> : AlgebraND { +public interface Nd4jArrayAlgebra> : AlgebraND { /** - * Wraps [INDArray] to [Nd4jArrayStructure]. + * Wraps [INDArray] to [N]. */ public fun INDArray.wrap(): Nd4jArrayStructure - /** - * Unwraps to or get [INDArray] from [StructureND]. - */ public val StructureND.ndArray: INDArray + get() = when { + !shape.contentEquals(this@Nd4jArrayAlgebra.shape) -> throw ShapeMismatchException( + this@Nd4jArrayAlgebra.shape, + shape + ) + this is Nd4jArrayStructure -> ndArray //TODO check strides + else -> { + TODO() + } + } - @OptIn(PerformancePitfall::class) - override fun structureND(shape: ShapeND, initializer: C.(IntArray) -> T): Nd4jArrayStructure { - @OptIn(UnsafeKMathAPI::class) - val struct: Nd4jArrayStructure = Nd4j.create(*shape.asArray())!!.wrap() - struct.indicesIterator().forEach { struct[it] = elementAlgebra.initializer(it) } + public override fun produce(initializer: C.(IntArray) -> T): Nd4jArrayStructure { + val struct = Nd4j.create(*shape)!!.wrap() + struct.indicesIterator().forEach { struct[it] = elementContext.initializer(it) } return struct } - @OptIn(PerformancePitfall::class) - override fun StructureND.map(transform: C.(T) -> T): Nd4jArrayStructure { + public override fun StructureND.map(transform: C.(T) -> T): Nd4jArrayStructure { val newStruct = ndArray.dup().wrap() - newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementAlgebra.transform(value) } + newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) } return newStruct } - @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class) - override fun StructureND.mapIndexed( + public override fun StructureND.mapIndexed( transform: C.(index: IntArray, T) -> T, ): Nd4jArrayStructure { - val new = Nd4j.create(*shape.asArray()).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementAlgebra.transform(idx, this[idx]) } + val new = Nd4j.create(*this@Nd4jArrayAlgebra.shape).wrap() + new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(idx, this[idx]) } return new } - @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class) - override fun zip( - left: StructureND, - right: StructureND, + public override fun combine( + a: StructureND, + b: StructureND, transform: C.(T, T) -> T, ): Nd4jArrayStructure { - require(left.shape.contentEquals(right.shape)) { "Can't zip tow structures of shape ${left.shape} and ${right.shape}" } - val new = Nd4j.create(*left.shape.asArray()).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementAlgebra.transform(left[idx], right[idx]) } + val new = Nd4j.create(*shape).wrap() + new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(a[idx], b[idx]) } return new } } @@ -76,15 +80,18 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND> : GroupOpsND, Nd4jArrayAlgebra { +public interface Nd4JArrayGroup> : GroupND, Nd4jArrayAlgebra { - override fun add(left: StructureND, right: StructureND): Nd4jArrayStructure = - left.ndArray.add(right.ndArray).wrap() + public override val zero: Nd4jArrayStructure + get() = Nd4j.zeros(*shape).wrap() - override operator fun StructureND.minus(arg: StructureND): Nd4jArrayStructure = - ndArray.sub(arg.ndArray).wrap() + public override fun add(a: StructureND, b: StructureND): Nd4jArrayStructure = + a.ndArray.add(b.ndArray).wrap() - override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = + public override operator fun StructureND.minus(b: StructureND): Nd4jArrayStructure = + ndArray.sub(b.ndArray).wrap() + + public override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() public fun multiply(a: StructureND, k: Number): Nd4jArrayStructure = @@ -98,34 +105,56 @@ public sealed interface Nd4jArrayGroupOps> : GroupOpsND * @param R the type of ring of structure elements. */ @OptIn(UnstableKMathAPI::class) -public sealed interface Nd4jArrayRingOps> : RingOpsND, Nd4jArrayGroupOps { +public interface Nd4jArrayRing> : RingND, Nd4JArrayGroup { - override fun multiply(left: StructureND, right: StructureND): Nd4jArrayStructure = - left.ndArray.mul(right.ndArray).wrap() + public override val one: Nd4jArrayStructure + get() = Nd4j.ones(*shape).wrap() + + public override fun multiply(a: StructureND, b: StructureND): Nd4jArrayStructure = + a.ndArray.mul(b.ndArray).wrap() // -// override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { +// public override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { // check(this) // return ndArray.sub(b).wrap() // } // -// override operator fun Nd4jArrayStructure.plus(b: Number): Nd4jArrayStructure { +// public override operator fun Nd4jArrayStructure.plus(b: Number): Nd4jArrayStructure { // check(this) // return ndArray.add(b).wrap() // } // -// override operator fun Number.minus(b: Nd4jArrayStructure): Nd4jArrayStructure { +// public override operator fun Number.minus(b: Nd4jArrayStructure): Nd4jArrayStructure { // check(b) // return b.ndArray.rsub(this).wrap() // } public companion object { + private val intNd4jArrayRingCache: ThreadLocal> = + ThreadLocal.withInitial { hashMapOf() } + + private val longNd4jArrayRingCache: ThreadLocal> = + ThreadLocal.withInitial { hashMapOf() } + + /** + * Creates an [RingND] for [Int] values or pull it from cache if it was created previously. + */ + public fun int(vararg shape: Int): Nd4jArrayRing = + intNd4jArrayRingCache.get().getOrPut(shape) { IntNd4jArrayRing(shape) } + + /** + * Creates an [RingND] for [Long] values or pull it from cache if it was created previously. + */ + public fun long(vararg shape: Int): Nd4jArrayRing = + longNd4jArrayRingCache.get().getOrPut(shape) { LongNd4jArrayRing(shape) } + /** * Creates a most suitable implementation of [RingND] using reified class. */ @Suppress("UNCHECKED_CAST") - public inline fun auto(): Nd4jArrayRingOps> = when { - T::class == Int::class -> IntRing.nd4j as Nd4jArrayRingOps> - else -> throw UnsupportedOperationException("This factory method only supports Long type.") + public inline fun auto(vararg shape: Int): Nd4jArrayRing> = when { + T::class == Int::class -> int(*shape) as Nd4jArrayRing> + T::class == Long::class -> long(*shape) as Nd4jArrayRing> + else -> throw UnsupportedOperationException("This factory method only supports Int and Long types.") } } } @@ -134,186 +163,155 @@ public sealed interface Nd4jArrayRingOps> : RingOpsND, * Represents [FieldND] over [Nd4jArrayStructure]. * * @param T the type of the element contained in ND structure. + * @param N the type of ND structure. * @param F the type field of structure elements. */ -public sealed interface Nd4jArrayField> : FieldOpsND, Nd4jArrayRingOps { +public interface Nd4jArrayField> : FieldND, Nd4jArrayRing { - override fun divide(left: StructureND, right: StructureND): Nd4jArrayStructure = - left.ndArray.div(right.ndArray).wrap() + public override fun divide(a: StructureND, b: StructureND): Nd4jArrayStructure = + a.ndArray.div(b.ndArray).wrap() public operator fun Number.div(b: StructureND): Nd4jArrayStructure = b.ndArray.rdiv(this).wrap() public companion object { + private val floatNd4jArrayFieldCache: ThreadLocal> = + ThreadLocal.withInitial { hashMapOf() } + + private val doubleNd4JArrayFieldCache: ThreadLocal> = + ThreadLocal.withInitial { hashMapOf() } + /** - * Creates a most suitable implementation of [FieldND] using reified class. + * Creates an [FieldND] for [Float] values or pull it from cache if it was created previously. + */ + public fun float(vararg shape: Int): Nd4jArrayRing = + floatNd4jArrayFieldCache.get().getOrPut(shape) { FloatNd4jArrayField(shape) } + + /** + * Creates an [FieldND] for [Double] values or pull it from cache if it was created previously. + */ + public fun real(vararg shape: Int): Nd4jArrayRing = + doubleNd4JArrayFieldCache.get().getOrPut(shape) { DoubleNd4jArrayField(shape) } + + /** + * Creates a most suitable implementation of [RingND] using reified class. */ @Suppress("UNCHECKED_CAST") - public inline fun auto(): Nd4jArrayField> = when { - T::class == Float::class -> FloatField.nd4j as Nd4jArrayField> - T::class == Double::class -> DoubleField.nd4j as Nd4jArrayField> + public inline fun auto(vararg shape: Int): Nd4jArrayField> = when { + T::class == Float::class -> float(*shape) as Nd4jArrayField> + T::class == Double::class -> real(*shape) as Nd4jArrayField> else -> throw UnsupportedOperationException("This factory method only supports Float and Double types.") } } } -/** - * Represents intersection of [ExtendedField] and [Field] over [Nd4jArrayStructure]. - */ -public sealed interface Nd4jArrayExtendedFieldOps> : - ExtendedFieldOps>, Nd4jArrayField, PowerOperations> { - - override fun sin(arg: StructureND): StructureND = Transforms.sin(arg.ndArray).wrap() - override fun cos(arg: StructureND): StructureND = Transforms.cos(arg.ndArray).wrap() - override fun asin(arg: StructureND): StructureND = Transforms.asin(arg.ndArray).wrap() - override fun acos(arg: StructureND): StructureND = Transforms.acos(arg.ndArray).wrap() - override fun atan(arg: StructureND): StructureND = Transforms.atan(arg.ndArray).wrap() - - override fun power(arg: StructureND, pow: Number): StructureND = - Transforms.pow(arg.ndArray, pow).wrap() - - override fun exp(arg: StructureND): StructureND = Transforms.exp(arg.ndArray).wrap() - override fun ln(arg: StructureND): StructureND = Transforms.log(arg.ndArray).wrap() - override fun sqrt(arg: StructureND): StructureND = Transforms.sqrt(arg.ndArray).wrap() - override fun sinh(arg: StructureND): StructureND = Transforms.sinh(arg.ndArray).wrap() - override fun cosh(arg: StructureND): StructureND = Transforms.cosh(arg.ndArray).wrap() - override fun tanh(arg: StructureND): StructureND = Transforms.tanh(arg.ndArray).wrap() - - override fun asinh(arg: StructureND): StructureND = - Nd4j.getExecutioner().exec(ASinh(arg.ndArray, arg.ndArray.ulike())).wrap() - - override fun acosh(arg: StructureND): StructureND = - Nd4j.getExecutioner().exec(ACosh(arg.ndArray, arg.ndArray.ulike())).wrap() - - override fun atanh(arg: StructureND): StructureND = Transforms.atanh(arg.ndArray).wrap() -} - /** * Represents [FieldND] over [Nd4jArrayDoubleStructure]. */ -public open class DoubleNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps { - override val elementAlgebra: DoubleField get() = DoubleField +public class DoubleNd4jArrayField(public override val shape: IntArray) : Nd4jArrayField { + public override val elementContext: DoubleField get() = DoubleField - override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() + public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asDoubleStructure() - @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class) - override val StructureND.ndArray: INDArray - get() = when (this) { - is Nd4jArrayStructure -> ndArray - else -> Nd4j.zeros(*shape.asArray()).also { - elements().forEach { (idx, value) -> it.putScalar(idx, value) } - } - } + override fun scale(a: StructureND, value: Double): Nd4jArrayStructure { + return a.ndArray.mul(value).wrap() + } - override fun scale(a: StructureND, value: Double): Nd4jArrayStructure = a.ndArray.mul(value).wrap() + public override operator fun StructureND.div(arg: Double): Nd4jArrayStructure { + return ndArray.div(arg).wrap() + } - override operator fun StructureND.div(arg: Double): Nd4jArrayStructure = ndArray.div(arg).wrap() + public override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure { + return ndArray.add(arg).wrap() + } - override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure = ndArray.add(arg).wrap() + public override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure { + return ndArray.sub(arg).wrap() + } - override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure = ndArray.sub(arg).wrap() + public override operator fun StructureND.times(arg: Double): Nd4jArrayStructure { + return ndArray.mul(arg).wrap() + } - override operator fun StructureND.times(arg: Double): Nd4jArrayStructure = ndArray.mul(arg).wrap() + public override operator fun Double.div(arg: StructureND): Nd4jArrayStructure { + return arg.ndArray.rdiv(this).wrap() + } - override operator fun Double.div(arg: StructureND): Nd4jArrayStructure = - arg.ndArray.rdiv(this).wrap() - - override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure = - arg.ndArray.rsub(this).wrap() - - public companion object : DoubleNd4jArrayFieldOps() + public override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure { + return arg.ndArray.rsub(this).wrap() + } } -public val DoubleField.nd4j: DoubleNd4jArrayFieldOps get() = DoubleNd4jArrayFieldOps - -public class DoubleNd4jArrayField(override val shape: ShapeND) : DoubleNd4jArrayFieldOps(), FieldND - -public fun DoubleField.nd4j(shapeFirst: Int, vararg shapeRest: Int): DoubleNd4jArrayField = - DoubleNd4jArrayField(ShapeND(shapeFirst, * shapeRest)) - - /** * Represents [FieldND] over [Nd4jArrayStructure] of [Float]. */ -public open class FloatNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps { - override val elementAlgebra: FloatField get() = FloatField +public class FloatNd4jArrayField(public override val shape: IntArray) : Nd4jArrayField { + public override val elementContext: FloatField + get() = FloatField - override fun INDArray.wrap(): Nd4jArrayStructure = asFloatStructure() - - @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class) - override val StructureND.ndArray: INDArray - get() = when (this) { - is Nd4jArrayStructure -> ndArray - else -> Nd4j.zeros(*shape.asArray()).also { - elements().forEach { (idx, value) -> it.putScalar(idx, value) } - } - } + public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asFloatStructure() override fun scale(a: StructureND, value: Double): StructureND = a.ndArray.mul(value).wrap() - override operator fun StructureND.div(arg: Float): Nd4jArrayStructure = + public override operator fun StructureND.div(arg: Float): Nd4jArrayStructure = ndArray.div(arg).wrap() - override operator fun StructureND.plus(arg: Float): Nd4jArrayStructure = + public override operator fun StructureND.plus(arg: Float): Nd4jArrayStructure = ndArray.add(arg).wrap() - override operator fun StructureND.minus(arg: Float): Nd4jArrayStructure = + public override operator fun StructureND.minus(arg: Float): Nd4jArrayStructure = ndArray.sub(arg).wrap() - override operator fun StructureND.times(arg: Float): Nd4jArrayStructure = + public override operator fun StructureND.times(arg: Float): Nd4jArrayStructure = ndArray.mul(arg).wrap() - override operator fun Float.div(arg: StructureND): Nd4jArrayStructure = + public override operator fun Float.div(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rdiv(this).wrap() - override operator fun Float.minus(arg: StructureND): Nd4jArrayStructure = + public override operator fun Float.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() - - public companion object : FloatNd4jArrayFieldOps() } -public class FloatNd4jArrayField(override val shape: ShapeND) : FloatNd4jArrayFieldOps(), RingND - -public val FloatField.nd4j: FloatNd4jArrayFieldOps get() = FloatNd4jArrayFieldOps - -public fun FloatField.nd4j(shapeFirst: Int, vararg shapeRest: Int): FloatNd4jArrayField = - FloatNd4jArrayField(ShapeND(shapeFirst, * shapeRest)) - /** * Represents [RingND] over [Nd4jArrayIntStructure]. */ -public open class IntNd4jArrayRingOps : Nd4jArrayRingOps { - override val elementAlgebra: IntRing get() = IntRing +public class IntNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayRing { + public override val elementContext: IntRing + get() = IntRing - override fun INDArray.wrap(): Nd4jArrayStructure = asIntStructure() + public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asIntStructure() - @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class) - override val StructureND.ndArray: INDArray - get() = when (this) { - is Nd4jArrayStructure -> ndArray - else -> Nd4j.zeros(*shape.asArray()).also { - elements().forEach { (idx, value) -> it.putScalar(idx, value) } - } - } - - override operator fun StructureND.plus(arg: Int): Nd4jArrayStructure = + public override operator fun StructureND.plus(arg: Int): Nd4jArrayStructure = ndArray.add(arg).wrap() - override operator fun StructureND.minus(arg: Int): Nd4jArrayStructure = + public override operator fun StructureND.minus(arg: Int): Nd4jArrayStructure = ndArray.sub(arg).wrap() - override operator fun StructureND.times(arg: Int): Nd4jArrayStructure = + public override operator fun StructureND.times(arg: Int): Nd4jArrayStructure = ndArray.mul(arg).wrap() - override operator fun Int.minus(arg: StructureND): Nd4jArrayStructure = + public override operator fun Int.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() - - public companion object : IntNd4jArrayRingOps() } -public val IntRing.nd4j: IntNd4jArrayRingOps get() = IntNd4jArrayRingOps +/** + * Represents [RingND] over [Nd4jArrayStructure] of [Long]. + */ +public class LongNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayRing { + public override val elementContext: LongRing + get() = LongRing -public class IntNd4jArrayRing(override val shape: ShapeND) : IntNd4jArrayRingOps(), RingND + public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asLongStructure() -public fun IntRing.nd4j(shapeFirst: Int, vararg shapeRest: Int): IntNd4jArrayRing = - IntNd4jArrayRing(ShapeND(shapeFirst, * shapeRest)) \ No newline at end of file + public override operator fun StructureND.plus(arg: Long): Nd4jArrayStructure = + ndArray.add(arg).wrap() + + public override operator fun StructureND.minus(arg: Long): Nd4jArrayStructure = + ndArray.sub(arg).wrap() + + public override operator fun StructureND.times(arg: Long): Nd4jArrayStructure = + ndArray.mul(arg).wrap() + + public override operator fun Long.minus(arg: StructureND): Nd4jArrayStructure = + arg.ndArray.rsub(this).wrap() +} diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt index fedad26e0..71887ca3c 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -25,7 +25,7 @@ private class Nd4jArrayIndicesIterator(private val iterateOver: INDArray) : Iter internal fun INDArray.indicesIterator(): Iterator = Nd4jArrayIndicesIterator(this) -private sealed class Nd4jArrayIteratorBase(protected val iterateOver: INDArray) : Iterator> { +private sealed class Nd4jArrayIteratorBase(protected val iterateOver: INDArray) : Iterator> { private var i: Int = 0 final override fun hasNext(): Boolean = i < iterateOver.length() @@ -48,6 +48,12 @@ private class Nd4jArrayDoubleIterator(iterateOver: INDArray) : Nd4jArrayIterator internal fun INDArray.realIterator(): Iterator> = Nd4jArrayDoubleIterator(this) +private class Nd4jArrayLongIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase(iterateOver) { + override fun getSingle(indices: LongArray) = iterateOver.getLong(*indices) +} + +internal fun INDArray.longIterator(): Iterator> = Nd4jArrayLongIterator(this) + private class Nd4jArrayIntIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase(iterateOver) { override fun getSingle(indices: LongArray) = iterateOver.getInt(*indices.toIntArray()) } diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt index 93fbc8f85..b9aa251d2 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt @@ -1,13 +1,13 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd4j import org.nd4j.linalg.api.ndarray.INDArray -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.MutableStructureND +import space.kscience.kmath.nd.StructureND /** * Represents a [StructureND] wrapping an [INDArray] object. @@ -16,45 +16,43 @@ import space.kscience.kmath.nd.* */ public sealed class Nd4jArrayStructure : MutableStructureND { /** - * The wrapped [INDArray]. Since KMath uses [Int] indexes, assuming the size of [INDArray] is less or equal to - * [Int.MAX_VALUE]. + * The wrapped [INDArray]. */ public abstract val ndArray: INDArray - override val shape: ShapeND get() = ShapeND(ndArray.shape().toIntArray()) + public override val shape: IntArray + get() = ndArray.shape().toIntArray() internal abstract fun elementsIterator(): Iterator> internal fun indicesIterator(): Iterator = ndArray.indicesIterator() - - @PerformancePitfall - override fun elements(): Sequence> = Sequence(::elementsIterator) + public override fun elements(): Sequence> = Sequence(::elementsIterator) } -public data class Nd4jArrayIntStructure(override val ndArray: INDArray) : Nd4jArrayStructure(), StructureNDOfInt { +private data class Nd4jArrayIntStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { override fun elementsIterator(): Iterator> = ndArray.intIterator() - - @OptIn(PerformancePitfall::class) override fun get(index: IntArray): Int = ndArray.getInt(*index) - - override fun getInt(index: IntArray): Int = ndArray.getInt(*index) - - @OptIn(PerformancePitfall::class) override fun set(index: IntArray, value: Int): Unit = run { ndArray.putScalar(index, value) } } /** * Wraps this [INDArray] to [Nd4jArrayStructure]. */ -public fun INDArray.asIntStructure(): Nd4jArrayIntStructure = Nd4jArrayIntStructure(this) +public fun INDArray.asIntStructure(): Nd4jArrayStructure = Nd4jArrayIntStructure(this) -public data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4jArrayStructure(), StructureNDOfDouble { +private data class Nd4jArrayLongStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { + override fun elementsIterator(): Iterator> = ndArray.longIterator() + override fun get(index: IntArray): Long = ndArray.getLong(*index.toLongArray()) + override fun set(index: IntArray, value: Long): Unit = run { ndArray.putScalar(index, value.toDouble()) } +} + +/** + * Wraps this [INDArray] to [Nd4jArrayStructure]. + */ +public fun INDArray.asLongStructure(): Nd4jArrayStructure = Nd4jArrayLongStructure(this) + +private data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { override fun elementsIterator(): Iterator> = ndArray.realIterator() - @OptIn(PerformancePitfall::class) override fun get(index: IntArray): Double = ndArray.getDouble(*index) - - override fun getDouble(index: IntArray): Double = ndArray.getDouble(*index) - - @OptIn(PerformancePitfall::class) override fun set(index: IntArray, value: Double): Unit = run { ndArray.putScalar(index, value) } } @@ -63,12 +61,9 @@ public data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4 */ public fun INDArray.asDoubleStructure(): Nd4jArrayStructure = Nd4jArrayDoubleStructure(this) -public data class Nd4jArrayFloatStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { +private data class Nd4jArrayFloatStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { override fun elementsIterator(): Iterator> = ndArray.floatIterator() - @PerformancePitfall override fun get(index: IntArray): Float = ndArray.getFloat(*index) - - @PerformancePitfall override fun set(index: IntArray, value: Float): Unit = run { ndArray.putScalar(index, value) } } diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt deleted file mode 100644 index 5905739f8..000000000 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.nd4j - -import org.nd4j.linalg.api.ndarray.INDArray -import org.nd4j.linalg.api.ops.impl.summarystats.Variance -import org.nd4j.linalg.api.ops.impl.transforms.strict.ACosh -import org.nd4j.linalg.api.ops.impl.transforms.strict.ASinh -import org.nd4j.linalg.factory.Nd4j -import org.nd4j.linalg.factory.ops.NDBase -import org.nd4j.linalg.ops.transforms.Transforms -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnsafeKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.api.TensorAlgebra -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra - -/** - * ND4J based [TensorAlgebra] implementation. - */ -public sealed interface Nd4jTensorAlgebra> : AnalyticTensorAlgebra { - - /** - * Wraps [INDArray] to [Nd4jArrayStructure]. - */ - public fun INDArray.wrap(): Nd4jArrayStructure - - /** - * Unwraps to or gets [INDArray] from [StructureND]. - */ - public val StructureND.ndArray: INDArray - - override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): Nd4jArrayStructure - - @OptIn(PerformancePitfall::class) - override fun StructureND.map(transform: A.(T) -> T): Nd4jArrayStructure = - structureND(shape) { index -> elementAlgebra.transform(get(index)) } - - @OptIn(PerformancePitfall::class) - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): Nd4jArrayStructure = - structureND(shape) { index -> elementAlgebra.transform(index, get(index)) } - - @OptIn(PerformancePitfall::class) - override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): Nd4jArrayStructure { - require(left.shape.contentEquals(right.shape)) - return structureND(left.shape) { index -> elementAlgebra.transform(left[index], right[index]) } - } - - override fun T.plus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.add(this).wrap() - override fun StructureND.plus(arg: T): Nd4jArrayStructure = ndArray.add(arg).wrap() - - override fun StructureND.plus(arg: StructureND): Nd4jArrayStructure = ndArray.add(arg.ndArray).wrap() - - override fun Tensor.plusAssign(value: T) { - ndArray.addi(value) - } - - override fun Tensor.plusAssign(arg: StructureND) { - ndArray.addi(arg.ndArray) - } - - override fun T.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() - override fun StructureND.minus(arg: T): Nd4jArrayStructure = ndArray.sub(arg).wrap() - override fun StructureND.minus(arg: StructureND): Nd4jArrayStructure = ndArray.sub(arg.ndArray).wrap() - - override fun Tensor.minusAssign(value: T) { - ndArray.rsubi(value) - } - - override fun Tensor.minusAssign(arg: StructureND) { - ndArray.subi(arg.ndArray) - } - - override fun T.times(arg: StructureND): Nd4jArrayStructure = arg.ndArray.mul(this).wrap() - - override fun StructureND.times(arg: T): Nd4jArrayStructure = - ndArray.mul(arg).wrap() - - override fun StructureND.times(arg: StructureND): Nd4jArrayStructure = ndArray.mul(arg.ndArray).wrap() - - override fun Tensor.timesAssign(value: T) { - ndArray.muli(value) - } - - override fun Tensor.timesAssign(arg: StructureND) { - ndArray.mmuli(arg.ndArray) - } - - override fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() - override fun Tensor.getTensor(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() - override fun StructureND.transposed(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() - override fun StructureND.dot(other: StructureND): Nd4jArrayStructure = ndArray.mmul(other.ndArray).wrap() - - override fun StructureND.min(dim: Int, keepDim: Boolean): Nd4jArrayStructure = - ndArray.min(keepDim, dim).wrap() - - override fun StructureND.sum(dim: Int, keepDim: Boolean): Nd4jArrayStructure = - ndArray.sum(keepDim, dim).wrap() - - override fun StructureND.max(dim: Int, keepDim: Boolean): Nd4jArrayStructure = - ndArray.max(keepDim, dim).wrap() - - @OptIn(UnsafeKMathAPI::class) - override fun Tensor.view(shape: ShapeND): Nd4jArrayStructure = ndArray.reshape(shape.asArray()).wrap() - - override fun Tensor.viewAs(other: StructureND): Nd4jArrayStructure = view(other.shape) - - override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = - ndBase.get().argmin(ndArray, keepDim, dim).asIntStructure() - - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor = - ndBase.get().argmax(ndArray, keepDim, dim).asIntStructure() - - override fun mean(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = - structureND.ndArray.mean(keepDim, dim).wrap() - - override fun exp(arg: StructureND): Nd4jArrayStructure = Transforms.exp(arg.ndArray).wrap() - override fun ln(arg: StructureND): Nd4jArrayStructure = Transforms.log(arg.ndArray).wrap() - override fun sqrt(arg: StructureND): Nd4jArrayStructure = Transforms.sqrt(arg.ndArray).wrap() - override fun cos(arg: StructureND): Nd4jArrayStructure = Transforms.cos(arg.ndArray).wrap() - override fun acos(arg: StructureND): Nd4jArrayStructure = Transforms.acos(arg.ndArray).wrap() - override fun cosh(arg: StructureND): Nd4jArrayStructure = Transforms.cosh(arg.ndArray).wrap() - - override fun acosh(arg: StructureND): Nd4jArrayStructure = - Nd4j.getExecutioner().exec(ACosh(arg.ndArray, arg.ndArray.ulike())).wrap() - - override fun sin(arg: StructureND): Nd4jArrayStructure = Transforms.sin(arg.ndArray).wrap() - override fun asin(arg: StructureND): Nd4jArrayStructure = Transforms.asin(arg.ndArray).wrap() - override fun sinh(arg: StructureND): Tensor = Transforms.sinh(arg.ndArray).wrap() - - override fun asinh(arg: StructureND): Nd4jArrayStructure = - Nd4j.getExecutioner().exec(ASinh(arg.ndArray, arg.ndArray.ulike())).wrap() - - override fun tan(arg: StructureND): Nd4jArrayStructure = Transforms.tan(arg.ndArray).wrap() - override fun atan(arg: StructureND): Nd4jArrayStructure = Transforms.atan(arg.ndArray).wrap() - override fun tanh(arg: StructureND): Nd4jArrayStructure = Transforms.tanh(arg.ndArray).wrap() - override fun atanh(arg: StructureND): Nd4jArrayStructure = Transforms.atanh(arg.ndArray).wrap() - override fun power(arg: StructureND, pow: Number): StructureND = Transforms.pow(arg.ndArray, pow).wrap() - override fun ceil(arg: StructureND): Nd4jArrayStructure = Transforms.ceil(arg.ndArray).wrap() - override fun floor(structureND: StructureND): Nd4jArrayStructure = Transforms.floor(structureND.ndArray).wrap() - override fun std(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = - structureND.ndArray.std(true, keepDim, dim).wrap() - - override fun T.div(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rdiv(this).wrap() - override fun StructureND.div(arg: T): Nd4jArrayStructure = ndArray.div(arg).wrap() - override fun StructureND.div(arg: StructureND): Nd4jArrayStructure = ndArray.div(arg.ndArray).wrap() - - override fun Tensor.divAssign(value: T) { - ndArray.divi(value) - } - - override fun Tensor.divAssign(arg: StructureND) { - ndArray.divi(arg.ndArray) - } - - override fun variance(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = - Nd4j.getExecutioner().exec(Variance(structureND.ndArray, true, true, dim)).wrap() - - private companion object { - private val ndBase: ThreadLocal = ThreadLocal.withInitial(::NDBase) - } -} - -/** - * [Double] specialization of [Nd4jTensorAlgebra]. - */ -public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { - - override val elementAlgebra: DoubleField get() = DoubleField - - override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() - - @OptIn(UnsafeKMathAPI::class) - override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): Nd4jArrayStructure { - val array: INDArray = Nd4j.zeros(*shape.asArray()) - val indices = ColumnStrides(shape) - indices.asSequence().forEach { index -> - array.putScalar(index, elementAlgebra.initializer(index)) - } - return array.wrap() - } - - - @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class) - override val StructureND.ndArray: INDArray - get() = when (this) { - is Nd4jArrayStructure -> ndArray - else -> Nd4j.zeros(*shape.asArray()).also { - elements().forEach { (idx, value) -> it.putScalar(idx, value) } - } - } - - override fun StructureND.valueOrNull(): Double? = - if (shape contentEquals ShapeND(1)) ndArray.getDouble(0) else null - - // TODO rewrite - override fun diagonalEmbedding( - diagonalEntries: StructureND, - offset: Int, - dim1: Int, - dim2: Int, - ): Tensor = DoubleTensorAlgebra.diagonalEmbedding(diagonalEntries, offset, dim1, dim2) - - override fun StructureND.sum(): Double = ndArray.sumNumber().toDouble() - override fun StructureND.min(): Double = ndArray.minNumber().toDouble() - override fun StructureND.max(): Double = ndArray.maxNumber().toDouble() - override fun mean(structureND: StructureND): Double = structureND.ndArray.meanNumber().toDouble() - override fun std(structureND: StructureND): Double = structureND.ndArray.stdNumber().toDouble() - override fun variance(structureND: StructureND): Double = structureND.ndArray.varNumber().toDouble() -} diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt index 401c57a7b..6c414cc13 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt @@ -1,10 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd4j -import space.kscience.kmath.misc.toIntExact - -internal fun LongArray.toIntArray(): IntArray = IntArray(size) { this[it].toIntExact() } +internal fun IntArray.toLongArray(): LongArray = LongArray(size) { this[it].toLong() } +internal fun LongArray.toIntArray(): IntArray = IntArray(size) { this[it].toInt() } diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt index 708778e77..c3874b249 100644 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt +++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt @@ -1,29 +1,19 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd4j import org.nd4j.linalg.factory.Nd4j -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.one -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.invoke -import kotlin.math.PI import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertTrue import kotlin.test.fail -@OptIn(PerformancePitfall::class) internal class Nd4jArrayAlgebraTest { @Test fun testProduce() { - val res = DoubleField.nd4j.structureND(2, 2) { it.sum().toDouble() } + val res = with(DoubleNd4jArrayField(intArrayOf(2, 2))) { produce { it.sum().toDouble() } } val expected = (Nd4j.create(2, 2) ?: fail()).asDoubleStructure() expected[intArrayOf(0, 0)] = 0.0 expected[intArrayOf(0, 1)] = 1.0 @@ -34,9 +24,7 @@ internal class Nd4jArrayAlgebraTest { @Test fun testMap() { - val res = IntRing.nd4j { - one(2, 2).map { it + it * 2 } - } + val res = with(IntNd4jArrayRing(intArrayOf(2, 2))) { one.map() { it + it * 2 } } val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() expected[intArrayOf(0, 0)] = 3 expected[intArrayOf(0, 1)] = 3 @@ -47,7 +35,7 @@ internal class Nd4jArrayAlgebraTest { @Test fun testAdd() { - val res = IntRing.nd4j { one(2, 2) + 25 } + val res = with(IntNd4jArrayRing(intArrayOf(2, 2))) { one + 25 } val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() expected[intArrayOf(0, 0)] = 26 expected[intArrayOf(0, 1)] = 26 @@ -55,14 +43,4 @@ internal class Nd4jArrayAlgebraTest { expected[intArrayOf(1, 1)] = 26 assertEquals(expected, res) } - - @Test - fun testSin() = DoubleField.nd4j{ - val initial = structureND(2, 2) { (i, j) -> if (i == j) PI / 2 else 0.0 } - val transformed = sin(initial) - val expected = structureND(2, 2) { (i, j) -> if (i == j) 1.0 else 0.0 } - - println(transformed) - assertTrue { StructureND.contentEquals(transformed, expected) } - } } diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt index d57eb2e2d..d59e04194 100644 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt +++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt @@ -1,13 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.nd4j import org.nd4j.linalg.factory.Nd4j -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.asList import space.kscience.kmath.nd.get import kotlin.test.Test import kotlin.test.assertEquals @@ -15,7 +13,6 @@ import kotlin.test.assertNotEquals import kotlin.test.fail internal class Nd4jArrayStructureTest { - @OptIn(PerformancePitfall::class) @Test fun testElements() { val nd = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!! @@ -28,7 +25,7 @@ internal class Nd4jArrayStructureTest { fun testShape() { val nd = Nd4j.rand(10, 2, 3, 6) ?: fail() val struct = nd.asDoubleStructure() - assertEquals(intArrayOf(10, 2, 3, 6).toList(), struct.shape.asList()) + assertEquals(intArrayOf(10, 2, 3, 6).toList(), struct.shape.toList()) } @Test @@ -73,7 +70,7 @@ internal class Nd4jArrayStructureTest { @Test fun testSet() { val nd = Nd4j.rand(17, 12, 4, 8)!! - val struct = nd.asIntStructure() + val struct = nd.asLongStructure() struct[intArrayOf(1, 2, 3, 4)] = 777 assertEquals(777, struct[1, 2, 3, 4]) } diff --git a/kmath-optimization/README.md b/kmath-optimization/README.md deleted file mode 100644 index 79a4f5d24..000000000 --- a/kmath-optimization/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-optimization - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-optimization:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-optimization:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-optimization:0.4.0-dev-1") -} -``` diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts deleted file mode 100644 index 7250d1f72..000000000 --- a/kmath-optimization/build.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -plugins { - id("space.kscience.gradle.mpp") -} - -kscience{ - jvm() - js() - native() -} - -kotlin.sourceSets { - - commonMain { - dependencies { - api(project(":kmath-coroutines")) - api(spclibs.atomicfu) - } - } -} - -readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL -} diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt deleted file mode 100644 index 07146625c..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.FeatureSet - -public class OptimizationValue(public val value: T) : OptimizationFeature { - override fun toString(): String = "Value($value)" -} - -public enum class FunctionOptimizationTarget : OptimizationFeature { - MAXIMIZE, - MINIMIZE -} - -public class FunctionOptimization( - override val features: FeatureSet, - public val expression: DifferentiableExpression, -) : OptimizationProblem { - - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as FunctionOptimization<*> - - if (features != other.features) return false - if (expression != other.expression) return false - - return true - } - - override fun hashCode(): Int { - var result = features.hashCode() - result = 31 * result + expression.hashCode() - return result - } - - override fun toString(): String = "FunctionOptimization(features=$features)" -} - -public fun FunctionOptimization.withFeatures( - vararg newFeature: OptimizationFeature, -): FunctionOptimization = FunctionOptimization( - features.with(*newFeature), - expression, -) - -/** - * Optimizes differentiable expression using specific [optimizer] form given [startingPoint]. - */ -public suspend fun DifferentiableExpression.optimizeWith( - optimizer: Optimizer>, - startingPoint: Map, - vararg features: OptimizationFeature, -): FunctionOptimization { - val problem = FunctionOptimization(FeatureSet.of(OptimizationStartPoint(startingPoint), *features), this) - return optimizer.optimize(problem) -} - -public val FunctionOptimization.resultValueOrNull: T? - get() = getFeature>()?.point?.let { expression(it) } - -public val FunctionOptimization.resultValue: T - get() = resultValueOrNull ?: error("Result is not present in $this") \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt deleted file mode 100644 index 0459d46ee..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.FeatureSet - -public abstract class OptimizationBuilder> { - public val features: MutableList = ArrayList() - - public fun addFeature(feature: OptimizationFeature) { - features.add(feature) - } - - public inline fun updateFeature(update: (T?) -> T) { - val existing = features.find { it.key == T::class } as? T - val new = update(existing) - if (existing != null) { - features.remove(existing) - } - addFeature(new) - } - - public abstract fun build(): R -} - -public fun OptimizationBuilder.startAt(startingPoint: Map) { - addFeature(OptimizationStartPoint(startingPoint)) -} - -public class FunctionOptimizationBuilder( - private val expression: DifferentiableExpression, -) : OptimizationBuilder>() { - override fun build(): FunctionOptimization = FunctionOptimization(FeatureSet.of(features), expression) -} - -public fun FunctionOptimization( - expression: DifferentiableExpression, - builder: FunctionOptimizationBuilder.() -> Unit, -): FunctionOptimization = FunctionOptimizationBuilder(expression).apply(builder).build() - -public suspend fun DifferentiableExpression.optimizeWith( - optimizer: Optimizer>, - startingPoint: Map, - builder: FunctionOptimizationBuilder.() -> Unit = {}, -): FunctionOptimization { - val problem = FunctionOptimization(this) { - startAt(startingPoint) - builder() - } - return optimizer.optimize(problem) -} - -public suspend fun DifferentiableExpression.optimizeWith( - optimizer: Optimizer>, - vararg startingPoint: Pair, - builder: FunctionOptimizationBuilder.() -> Unit = {}, -): FunctionOptimization { - val problem = FunctionOptimization(this) { - startAt(mapOf(*startingPoint)) - builder() - } - return optimizer.optimize(problem) -} - - -@OptIn(UnstableKMathAPI::class) -public class XYOptimizationBuilder( - public val data: XYColumnarData, - public val model: DifferentiableExpression, -) : OptimizationBuilder() { - - public var pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY - public var pointWeight: PointWeight = PointWeight.byYSigma - - override fun build(): XYFit = XYFit( - data, - model, - FeatureSet.of(features), - pointToCurveDistance, - pointWeight - ) -} - -@OptIn(UnstableKMathAPI::class) -public fun XYOptimization( - data: XYColumnarData, - model: DifferentiableExpression, - builder: XYOptimizationBuilder.() -> Unit, -): XYFit = XYOptimizationBuilder(data, model).apply(builder).build() \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt deleted file mode 100644 index 9fdcfc53d..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.NamedMatrix -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.* -import kotlin.reflect.KClass - -public interface OptimizationFeature : Feature { - // enforce toString override - override fun toString(): String -} - -public interface OptimizationProblem : Featured { - public val features: FeatureSet - override fun getFeature(type: KClass): F? = features.getFeature(type) -} - -public inline fun OptimizationProblem<*>.getFeature(): F? = getFeature(F::class) - -public open class OptimizationStartPoint(public val point: Map) : OptimizationFeature { - override fun toString(): String = "StartPoint($point)" -} - - -public interface OptimizationPrior : OptimizationFeature, DifferentiableExpression { - override val key: FeatureKey get() = OptimizationPrior::class -} - -/** - * Covariance matrix for - */ -public class OptimizationCovariance(public val covariance: NamedMatrix) : OptimizationFeature { - override fun toString(): String = "Covariance($covariance)" -} - -/** - * Get the starting point for optimization. Throws error if not defined. - */ -public val OptimizationProblem.startPoint: Map - get() = getFeature>()?.point - ?: error("Starting point not defined in $this") - -public open class OptimizationResult(public val point: Map) : OptimizationFeature { - override fun toString(): String = "Result($point)" -} - -public val OptimizationProblem.resultPointOrNull: Map? - get() = getFeature>()?.point - -public val OptimizationProblem.resultPoint: Map - get() = resultPointOrNull ?: error("Result is not present in $this") - -public class OptimizationLog(private val loggable: Loggable) : Loggable by loggable, OptimizationFeature { - override fun toString(): String = "Log($loggable)" -} - -/** - * Free parameters of the optimization - */ -public class OptimizationParameters(public val symbols: List) : OptimizationFeature { - public constructor(vararg symbols: Symbol) : this(listOf(*symbols)) - - override fun toString(): String = "Parameters($symbols)" -} - -/** - * Maximum allowed number of iterations - */ -public class OptimizationIterations(public val maxIterations: Int) : OptimizationFeature { - override fun toString(): String = "Iterations($maxIterations)" -} - - diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt deleted file mode 100644 index 41dcbf770..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization - -public interface Optimizer> { - public suspend fun optimize(problem: P): P -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt deleted file mode 100644 index b698584aa..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.* -import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.log -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.DoubleL2Norm -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.math.abs - - -public class QowRuns(public val runs: Int) : OptimizationFeature { - init { - require(runs >= 1) { "Number of runs must be more than zero" } - } - - override fun toString(): String = "QowRuns(runs=$runs)" -} - - -/** - * An optimizer based onf Fyodor Tkachev's quasi-optimal weights method. - * See [the article](http://arxiv.org/abs/physics/0604127). - */ -@UnstableKMathAPI -public object QowOptimizer : Optimizer { - - private val linearSpace: LinearSpace = Double.algebra.linearSpace - private val solver: LinearSolver = linearSpace.lupSolver() - - @OptIn(UnstableKMathAPI::class) - private class QoWeight( - val problem: XYFit, - val freeParameters: Map, - ) : SymbolIndexer { - val size get() = freeParameters.size - - override val symbols: List = freeParameters.keys.toList() - - val data get() = problem.data - - val allParameters by lazy { - problem.startPoint + freeParameters - } - - /** - * Derivatives of the spectrum over parameters. First index in the point number, second one - index of parameter - */ - val derivs: Matrix by lazy { - linearSpace.buildMatrix(problem.data.size, symbols.size) { d, s -> - problem.distance(d).derivative(symbols[s]).invoke(allParameters) - } - } - - /** - * Array of dispersions in each point - */ - val dispersion: Point by lazy { - DoubleBuffer(problem.data.size) { d -> - 1.0 / problem.weight(d).invoke(allParameters) - } - } - - val prior: DifferentiableExpression? - get() = problem.getFeature>()?.withDefaultArgs(allParameters) - - override fun toString(): String = freeParameters.toString() - } - - /** - * The signed distance from the model to the [d]-th point of data. - */ - private fun QoWeight.distance(d: Int, parameters: Map): Double = - problem.distance(d)(allParameters + parameters) - - - /** - * The derivative of [distance] - */ - private fun QoWeight.distanceDerivative(symbol: Symbol, d: Int, parameters: Map): Double = - problem.distance(d).derivative(symbol).invoke(allParameters + parameters) - - /** - * Theoretical covariance of weight functions - * - * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 - */ - private fun QoWeight.covarF(): Matrix = - linearSpace.matrix(size, size).symmetric { s1, s2 -> - (0 until data.size).sumOf { d -> derivs[d, s1] * derivs[d, s2] / dispersion[d] } - } - - /** - * Experimental covariance Eq (22) from - * http://arxiv.org/abs/physics/0604127 - */ - private fun QoWeight.covarFExp(theta: Map): Matrix = - with(linearSpace) { - /* - * Важно! Если не делать предварителього вычисления этих производных, то - * количество вызывов функции будет dim^2 вместо dim Первый индекс - - * номер точки, второй - номер переменной, по которой берется производная - */ - val eqvalues = linearSpace.buildMatrix(data.size, size) { d, s -> - distance(d, theta) * derivs[d, s] / dispersion[d] - } - - buildMatrix(size, size) { s1, s2 -> - (0 until data.size).sumOf { d -> eqvalues[d, s2] * eqvalues[d, s1] } - } - } - - /** - * Equation derivatives for Newton run - */ - private fun QoWeight.getEqDerivValues( - theta: Map = freeParameters, - ): Matrix = with(linearSpace) { - //Derivative of k Eq over l parameter - val sderiv = buildMatrix(data.size, size) { d, s -> - distanceDerivative(symbols[s], d, theta) - } - - buildMatrix(size, size) { s1, s2 -> - val base = (0 until data.size).sumOf { d -> - require(dispersion[d] > 0) - sderiv[d, s2] * derivs[d, s1] / dispersion[d] - } - prior?.let { prior -> - //Check if this one is correct - val pi = prior(theta) - val deriv1 = prior.derivative(symbols[s1])(theta) - val deriv2 = prior.derivative(symbols[s2])(theta) - base + deriv1 * deriv2 / pi / pi - } ?: base - } - } - - - /** - * Quasi optimal weights equations values - */ - private fun QoWeight.getEqValues(theta: Map): Point { - val distances = DoubleBuffer(data.size) { d -> distance(d, theta) } - return DoubleBuffer(size) { s -> - val base = (0 until data.size).sumOf { d -> distances[d] * derivs[d, s] / dispersion[d] } - //Prior probability correction - prior?.let { prior -> - base - prior.derivative(symbols[s]).invoke(theta) / prior(theta) - } ?: base - } - } - - - private fun QoWeight.newtonianStep( - theta: Map, - eqValues: Point, - ): QoWeight = linearSpace { - val start = theta.toPoint() - val invJacob = solver.inverse(getEqDerivValues(theta)) - - val step = invJacob.dot(eqValues) - return QoWeight(problem, theta + (start - step).toMap()) - } - - private fun QoWeight.newtonianRun( - maxSteps: Int = 100, - tolerance: Double = 0.0, - fast: Boolean = false, - ): QoWeight { - - val logger = problem.getFeature() - - var dis: Double //discrepancy value - - var par = freeParameters - - logger?.log { "Starting newtonian iteration from: \n\t$allParameters" } - - var eqvalues = getEqValues(par) //Values of the weight functions - - dis = DoubleL2Norm.norm(eqvalues) // discrepancy - logger?.log { "Starting discrepancy is $dis" } - var i = 0 - var flag = false - while (!flag) { - i++ - logger?.log { "Starting step number $i" } - - val currentSolution = if (fast) { - //Matrix values in the point of weight computation - newtonianStep(freeParameters, eqvalues) - } else { - //Matrix values in a current point - newtonianStep(par, eqvalues) - } - // здесь должен стоять учет границ параметров - logger?.log { "Parameter values after step are: \n\t$currentSolution" } - - eqvalues = getEqValues(currentSolution.freeParameters) - val currentDis = DoubleL2Norm.norm(eqvalues)// discrepancy after the step - - logger?.log { "The discrepancy after step is: $currentDis." } - - if (currentDis >= dis && i > 1) { - //Check if one step is made - flag = true - logger?.log { "The discrepancy does not decrease. Stopping iteration." } - } else if (abs(dis - currentDis) <= tolerance) { - flag = true - par = currentSolution.freeParameters - logger?.log { "Relative discrepancy tolerance threshold is reached. Stopping iteration." } - } else { - par = currentSolution.freeParameters - dis = currentDis - } - if (i >= maxSteps) { - flag = true - logger?.log { "Maximum number of iterations reached. Stopping iteration." } - } - } - - return QoWeight(problem, par) - } - - private fun QoWeight.covariance(): NamedMatrix { - val logger = problem.getFeature() - - logger?.log { - """ - Starting errors estimation using quasi-optimal weights method. The starting weight is: - $allParameters - """.trimIndent() - } - - val covar = solver.inverse(getEqDerivValues()) - //TODO fix eigenvalues check -// val decomposition = EigenDecomposition(covar.matrix) -// var valid = true -// for (lambda in decomposition.realEigenvalues) { -// if (lambda <= 0) { -// logger?.log { "The covariance matrix is not positive defined. Error estimation is not valid" } -// valid = false -// } -// } - logger?.log { - "Covariance matrix:" + "\n" + NamedMatrix.toStringWithSymbols(covar, this) - } - return covar.named(symbols) - } - - override suspend fun optimize(problem: XYFit): XYFit { - val qowRuns = problem.getFeature()?.runs ?: 2 - val iterations = problem.getFeature()?.maxIterations ?: 50 - - val freeParameters: Map = problem.getFeature()?.let { op -> - problem.startPoint.filterKeys { it in op.symbols } - } ?: problem.startPoint - - var qow = QoWeight(problem, freeParameters) - var res = qow.newtonianRun(maxSteps = iterations) - repeat(qowRuns - 1) { - qow = QoWeight(problem, res.freeParameters) - res = qow.newtonianRun(maxSteps = iterations) - } - val covariance = res.covariance() - return res.problem.withFeature(OptimizationResult(res.freeParameters), OptimizationCovariance(covariance)) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt deleted file mode 100644 index 9e5396491..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.optimization - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.data.indices -import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.misc.Loggable -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.bindSymbol -import kotlin.math.pow - -/** - * Specify the way to compute distance from point to the curve as DifferentiableExpression - */ -public interface PointToCurveDistance : OptimizationFeature { - public fun distance(problem: XYFit, index: Int): DifferentiableExpression - - public companion object { - public val byY: PointToCurveDistance = object : PointToCurveDistance { - override fun distance(problem: XYFit, index: Int): DifferentiableExpression { - val x = problem.data.x[index] - val y = problem.data.y[index] - - return object : DifferentiableExpression { - override fun derivativeOrNull( - symbols: List, - ): Expression? = problem.model.derivativeOrNull(symbols)?.let { derivExpression -> - Expression { arguments -> - derivExpression.invoke(arguments + (Symbol.x to x)) - } - } - - override fun invoke(arguments: Map): Double = - problem.model(arguments + (Symbol.x to x)) - y - } - } - - override fun toString(): String = "PointToCurveDistanceByY" - } - } -} - -/** - * Compute a wight of the point. The more the weight, the more impact this point will have on the fit. - * By default, uses Dispersion^-1 - */ -public interface PointWeight : OptimizationFeature { - public fun weight(problem: XYFit, index: Int): DifferentiableExpression - - public companion object { - public fun bySigma(sigmaSymbol: Symbol): PointWeight = object : PointWeight { - override fun weight(problem: XYFit, index: Int): DifferentiableExpression = - object : DifferentiableExpression { - override fun invoke(arguments: Map): Double { - return problem.data[sigmaSymbol]?.get(index)?.pow(-2) ?: 1.0 - } - - override fun derivativeOrNull(symbols: List): Expression = Expression { 0.0 } - } - - override fun toString(): String = "PointWeightBySigma($sigmaSymbol)" - - } - - public val byYSigma: PointWeight = bySigma(Symbol.yError) - } -} - -/** - * A fit problem for X-Y-Yerr data. Also known as "least-squares" problem. - */ -public class XYFit( - public val data: XYColumnarData, - public val model: DifferentiableExpression, - override val features: FeatureSet, - internal val pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, - internal val pointWeight: PointWeight = PointWeight.byYSigma, - public val xSymbol: Symbol = Symbol.x, -) : OptimizationProblem { - public fun distance(index: Int): DifferentiableExpression = pointToCurveDistance.distance(this, index) - - public fun weight(index: Int): DifferentiableExpression = pointWeight.weight(this, index) -} - -public fun XYFit.withFeature(vararg features: OptimizationFeature): XYFit { - return XYFit(data, model, this.features.with(*features), pointToCurveDistance, pointWeight) -} - -public suspend fun XYColumnarData.fitWith( - optimizer: Optimizer, - modelExpression: DifferentiableExpression, - startingPoint: Map, - vararg features: OptimizationFeature = emptyArray(), - xSymbol: Symbol = Symbol.x, - pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, - pointWeight: PointWeight = PointWeight.byYSigma, -): XYFit { - var actualFeatures = FeatureSet.of(*features, OptimizationStartPoint(startingPoint)) - - if (actualFeatures.getFeature() == null) { - actualFeatures = actualFeatures.with(OptimizationLog(Loggable.console)) - } - val problem = XYFit( - this, - modelExpression, - actualFeatures, - pointToCurveDistance, - pointWeight, - xSymbol - ) - return optimizer.optimize(problem) -} - -/** - * Fit given data with a model provided as an expression - */ -public suspend fun XYColumnarData.fitWith( - optimizer: Optimizer, - processor: AutoDiffProcessor, - startingPoint: Map, - vararg features: OptimizationFeature = emptyArray(), - xSymbol: Symbol = Symbol.x, - pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, - pointWeight: PointWeight = PointWeight.byYSigma, - model: A.(I) -> I, -): XYFit where A : ExtendedField, A : ExpressionAlgebra { - val modelExpression: DifferentiableExpression = processor.differentiate { - val x = bindSymbol(xSymbol) - model(x) - } - - return fitWith( - optimizer = optimizer, - modelExpression = modelExpression, - startingPoint = startingPoint, - features = features, - xSymbol = xSymbol, - pointToCurveDistance = pointToCurveDistance, - pointWeight = pointWeight - ) -} - -/** - * Compute chi squared value for completed fit. Return null for incomplete fit - */ -public val XYFit.chiSquaredOrNull: Double? - get() { - val result = startPoint + (resultPointOrNull ?: return null) - - return data.indices.sumOf { index -> - - val x = data.x[index] - val y = data.y[index] - val yErr = data[Symbol.yError]?.get(index) ?: 1.0 - - val mu = model.invoke(result + (xSymbol to x)) - - ((y - mu) / yErr).pow(2) - } - } - -public val XYFit.dof: Int - get() = data.size - (getFeature()?.symbols?.size ?: startPoint.size) \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt deleted file mode 100644 index 8ab9de48d..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.data.indices -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.derivative -import kotlin.math.PI -import kotlin.math.ln -import kotlin.math.pow -import kotlin.math.sqrt - - -private val oneOver2Pi = 1.0 / sqrt(2 * PI) - -@UnstableKMathAPI -internal fun XYFit.logLikelihood(): DifferentiableExpression = object : DifferentiableExpression { - override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> - data.indices.sumOf { index -> - val d = distance(index)(arguments) - val weight = weight(index)(arguments) - val weightDerivative = weight(index).derivative(symbols)(arguments) - - // -1 / (sqrt(2 PI) * sigma) + 2 (x-mu)/ 2 sigma^2 * d mu/ d theta - (x-mu)^2 / 2 * d w/ d theta - return@sumOf -oneOver2Pi * sqrt(weight) + //offset derivative - d * model.derivative(symbols)(arguments) * weight - //model derivative - d.pow(2) * weightDerivative / 2 //weight derivative - } - } - - override fun invoke(arguments: Map): Double { - return data.indices.sumOf { index -> - val d = distance(index)(arguments) - val weight = weight(index)(arguments) - //1/sqrt(2 PI sigma^2) - (x-mu)^2/ (2 * sigma^2) - oneOver2Pi * ln(weight) - d.pow(2) * weight - } / 2 - } - -} - -/** - * Optimize given XY (least squares) [problem] using this function [Optimizer]. - * The problem is treated as maximum likelihood problem and is done via maximizing logarithmic likelihood, respecting - * possible weight dependency on the model and parameters. - */ -@UnstableKMathAPI -public suspend fun Optimizer>.maximumLogLikelihood(problem: XYFit): XYFit { - val functionOptimization = FunctionOptimization(problem.features, problem.logLikelihood()) - val result = optimize(functionOptimization.withFeatures(FunctionOptimizationTarget.MAXIMIZE)) - return XYFit(problem.data, problem.model, result.features) -} - -@UnstableKMathAPI -public suspend fun Optimizer>.maximumLogLikelihood( - data: XYColumnarData, - model: DifferentiableExpression, - builder: XYOptimizationBuilder.() -> Unit, -): XYFit = maximumLogLikelihood(XYOptimization(data, model, builder)) diff --git a/kmath-optimization/src/commonMain/tmp/QowFit.kt b/kmath-optimization/src/commonMain/tmp/QowFit.kt deleted file mode 100644 index c78aef401..000000000 --- a/kmath-optimization/src/commonMain/tmp/QowFit.kt +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.optimization.qow - -import space.kscience.kmath.data.ColumnarData -import space.kscience.kmath.data.XYErrorColumnarData -import space.kscience.kmath.expressions.* -import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.optimization.OptimizationFeature -import space.kscience.kmath.optimization.OptimizationProblemFactory -import space.kscience.kmath.optimization.OptimizationResult -import space.kscience.kmath.optimization.XYOptimization -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.DoubleL2Norm -import kotlin.math.pow - - -private typealias ParamSet = Map - -@OptIn(UnstableKMathAPI::class) -public class QowFit( - override val symbols: List, - private val space: LinearSpace, - private val solver: LinearSolver, -) : XYOptimization, SymbolIndexer { - - private var logger: FitLogger? = null - - private var startingPoint: Map = TODO() - private var covariance: Matrix? = TODO() - private val prior: DifferentiableExpression>? = TODO() - private var data: XYErrorColumnarData = TODO() - private var model: DifferentiableExpression> = TODO() - - private val features = HashSet() - - override fun update(result: OptimizationResult) { - TODO("Not yet implemented") - } - - override val algebra: Field - get() = TODO("Not yet implemented") - - override fun data( - dataSet: ColumnarData, - xSymbol: Symbol, - ySymbol: Symbol, - xErrSymbol: Symbol?, - yErrSymbol: Symbol?, - ) { - TODO("Not yet implemented") - } - - override fun model(model: (Double) -> DifferentiableExpression) { - TODO("Not yet implemented") - } - - private var x: Symbol = Symbol.x - - /** - * The signed distance from the model to the [i]-th point of data. - */ - private fun distance(i: Int, parameters: Map): Double = - model(parameters + (x to data.x[i])) - data.y[i] - - - /** - * The derivative of [distance] - * TODO use expressions instead - */ - private fun distanceDerivative(symbol: Symbol, i: Int, parameters: Map): Double = - model.derivative(symbol)(parameters + (x to data.x[i])) - - /** - * The dispersion of [i]-th data point - */ - private fun getDispersion(i: Int, parameters: Map): Double = data.yErr[i].pow(2) - - private fun getCovariance(weight: QoWeight): Matrix = solver.inverse(getEqDerivValues(weight)) - - /** - * Теоретическая ковариация весовых функций. - * - * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 - */ - private fun covarF(weight: QoWeight): Matrix = space.buildSymmetricMatrix(symbols.size) { k, l -> - (0 until data.size).sumOf { i -> weight.derivs[k, i] * weight.derivs[l, i] / weight.dispersion[i] } - } - - /** - * Экспериментальная ковариация весов. Формула (22) из - * http://arxiv.org/abs/physics/0604127 - * - * @param source - * @param set - * @param fitPars - * @param weight - * @return - */ - private fun covarFExp(weight: QoWeight, theta: Map): Matrix = space.run { - /* - * Важно! Если не делать предварителього вычисления этих производных, то - * количество вызывов функции будет dim^2 вместо dim Первый индекс - - * номер точки, второй - номер переменной, по которой берется производная - */ - val eqvalues = buildMatrix(data.size, symbols.size) { i, l -> - distance(i, theta) * weight.derivs[l, i] / weight.dispersion[i] - } - - buildMatrix(symbols.size, symbols.size) { k, l -> - (0 until data.size).sumOf { i -> eqvalues[i, l] * eqvalues[i, k] } - } - } - - /** - * производные уравнений для метода Ньютона - * - * @param source - * @param set - * @param fitPars - * @param weight - * @return - */ - private fun getEqDerivValues( - weight: QoWeight, theta: Map = weight.theta, - ): Matrix = space.run { - val fitDim = symbols.size - //Возвращает производную k-того Eq по l-тому параметру - val res = Array(fitDim) { DoubleArray(fitDim) } - val sderiv = buildMatrix(data.size, symbols.size) { i, l -> - distanceDerivative(symbols[l], i, theta) - } - - buildMatrix(symbols.size, symbols.size) { k, l -> - val base = (0 until data.size).sumOf { i -> - require(weight.dispersion[i] > 0) - sderiv[i, l] * weight.derivs[k, i] / weight.dispersion[i] - } - prior?.let { prior -> - //Check if this one is correct - val pi = prior(theta) - val deriv1 = prior.derivative(symbols[k])(theta) - val deriv2 = prior.derivative(symbols[l])(theta) - base + deriv1 * deriv2 / pi / pi - } ?: base - } - } - - - /** - * Значения уравнений метода квазиоптимальных весов - * - * @param source - * @param set - * @param fitPars - * @param weight - * @return - */ - private fun getEqValues(weight: QoWeight, theta: Map = weight.theta): Point { - val distances = DoubleBuffer(data.size) { i -> distance(i, theta) } - - return DoubleBuffer(symbols.size) { k -> - val base = (0 until data.size).sumOf { i -> distances[i] * weight.derivs[k, i] / weight.dispersion[i] } - //Поправка на априорную вероятность - prior?.let { prior -> - base - prior.derivative(symbols[k])(theta) / prior(theta) - } ?: base - } - } - - - /** - * The state of QOW fitter - * Created by Alexander Nozik on 17-Oct-16. - */ - private inner class QoWeight( - val theta: Map, - ) { - - init { - require(data.size > 0) { "The state does not contain data" } - } - - /** - * Derivatives of the spectrum over parameters. First index in the point number, second one - index of parameter - */ - val derivs: Matrix by lazy { - space.buildMatrix(data.size, symbols.size) { i, k -> - distanceDerivative(symbols[k], i, theta) - } - } - - /** - * Array of dispersions in each point - */ - val dispersion: Point by lazy { - DoubleBuffer(data.size) { i -> getDispersion(i, theta) } - } - - } - - private fun newtonianStep( - weight: QoWeight, - par: Map, - eqvalues: Point, - ): Map = space.run { - val start = par.toPoint() - val invJacob = solver.inverse(getEqDerivValues(weight, par)) - - val step = invJacob.dot(eqvalues) - return par + (start - step).toMap() - } - - private fun newtonianRun( - weight: QoWeight, - maxSteps: Int = 100, - tolerance: Double = 0.0, - fast: Boolean = false, - ): ParamSet { - - var dis: Double//норма невязки - // Для удобства работаем всегда с полным набором параметров - var par = startingPoint - - logger?.log { "Starting newtonian iteration from: \n\t$par" } - - var eqvalues = getEqValues(weight, par)//значения функций - - dis = DoubleL2Norm.norm(eqvalues)// невязка - logger?.log { "Starting discrepancy is $dis" } - var i = 0 - var flag = false - while (!flag) { - i++ - logger?.log { "Starting step number $i" } - - val currentSolution = if (fast) { - //Берет значения матрицы в той точке, где считается вес - newtonianStep(weight, weight.theta, eqvalues) - } else { - //Берет значения матрицы в точке par - newtonianStep(weight, par, eqvalues) - } - // здесь должен стоять учет границ параметров - logger?.log { "Parameter values after step are: \n\t$currentSolution" } - - eqvalues = getEqValues(weight, currentSolution) - val currentDis = DoubleL2Norm.norm(eqvalues)// невязка после шага - - logger?.log { "The discrepancy after step is: $currentDis." } - - if (currentDis >= dis && i > 1) { - //дополнительно проверяем, чтобы был сделан хотя бы один шаг - flag = true - logger?.log { "The discrepancy does not decrease. Stopping iteration." } - } else { - par = currentSolution - dis = currentDis - } - if (i >= maxSteps) { - flag = true - logger?.log { "Maximum number of iterations reached. Stopping iteration." } - } - if (dis <= tolerance) { - flag = true - logger?.log { "Tolerance threshold is reached. Stopping iteration." } - } - } - - return par - } - - -// -// override fun run(state: FitState, parentLog: History?, meta: Meta): FitResult { -// val log = Chronicle("QOW", parentLog) -// val action = meta.getString(FIT_STAGE_TYPE, TASK_RUN) -// log.report("QOW fit engine started task '{}'", action) -// return when (action) { -// TASK_SINGLE -> makeRun(state, log, meta) -// TASK_COVARIANCE -> generateErrors(state, log, meta) -// TASK_RUN -> { -// var res = makeRun(state, log, meta) -// res = makeRun(res.optState().get(), log, meta) -// generateErrors(res.optState().get(), log, meta) -// } -// else -> throw IllegalArgumentException("Unknown task") -// } -// } - -// private fun makeRun(state: FitState, log: History, meta: Meta): FitResult { -// /*Инициализация объектов, задание исходных значений*/ -// log.report("Starting fit using quasioptimal weights method.") -// -// val fitPars = getFitPars(state, meta) -// -// val curWeight = QoWeight(state, fitPars, state.parameters) -// -// // вычисляем вес в allPar. Потом можно будет попробовать ручное задание веса -// log.report("The starting weight is: \n\t{}", -// MathUtils.toString(curWeight.theta)) -// -// //Стартовая точка такая же как и параметр веса -// /*Фитирование*/ -// val res = newtonianRun(state, curWeight, log, meta) -// -// /*Генерация результата*/ -// -// return FitResult.build(state.edit().setPars(res).build(), *fitPars) -// } - - /** - * generateErrors. - */ - private fun generateErrors(): Matrix { - logger?.log { """ - Starting errors estimation using quasioptimal weights method. The starting weight is: - ${curWeight.theta} - """.trimIndent()} - val curWeight = QoWeight(startingPoint) - - val covar = getCovariance(curWeight) - - val decomposition = EigenDecomposition(covar.matrix) - var valid = true - for (lambda in decomposition.realEigenvalues) { - if (lambda <= 0) { - log.report("The covariance matrix is not positive defined. Error estimation is not valid") - valid = false - } - } - } - - - override suspend fun optimize(): OptimizationResult { - val curWeight = QoWeight(startingPoint) - logger?.log { - """ - Starting fit using quasioptimal weights method. The starting weight is: - ${curWeight.theta} - """.trimIndent() - } - val res = newtonianRun(curWeight) - } - - - companion object : OptimizationProblemFactory { - override fun build(symbols: List): QowFit { - TODO("Not yet implemented") - } - - - /** - * Constant `QOW_ENGINE_NAME="QOW"` - */ - const val QOW_ENGINE_NAME = "QOW" - - /** - * Constant `QOW_METHOD_FAST="fast"` - */ - const val QOW_METHOD_FAST = "fast" - - - } -} - diff --git a/kmath-optimization/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt deleted file mode 100644 index 912fa22eb..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * - * @version $Id$ - */ -internal class AnalyticalGradientCalculator(fcn: MultiFunction?, state: MnUserTransformation, checkGradient: Boolean) : - GradientCalculator { - private val function: MultiFunction? - private val theCheckGradient: Boolean - private val theTransformation: MnUserTransformation - fun checkGradient(): Boolean { - return theCheckGradient - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters): FunctionGradient { -// double[] grad = theGradCalc.gradientValue(theTransformation.andThen(par.vec()).data()); - val point: DoubleArray = theTransformation.transform(par.vec()).toArray() - require(!(function.getDimension() !== theTransformation.parameters().size())) { "Invalid parameter size" } - val v: RealVector = ArrayRealVector(par.vec().getDimension()) - for (i in 0 until par.vec().getDimension()) { - val ext: Int = theTransformation.extOfInt(i) - if (theTransformation.parameter(ext).hasLimits()) { - val dd: Double = theTransformation.dInt2Ext(i, par.vec().getEntry(i)) - v.setEntry(i, dd * function.derivValue(ext, point)) - } else { - v.setEntry(i, function.derivValue(ext, point)) - } - } - return FunctionGradient(v) - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters, grad: FunctionGradient?): FunctionGradient { - return gradient(par) - } - - init { - function = fcn - theTransformation = state - theCheckGradient = checkGradient - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimizer.kt deleted file mode 100644 index 9363492ad..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimizer.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class CombinedMinimizer : ModularFunctionMinimizer() { - private val theMinBuilder: CombinedMinimumBuilder = CombinedMinimumBuilder() - private val theMinSeedGen: MnSeedGenerator = MnSeedGenerator() - override fun builder(): MinimumBuilder { - return theMinBuilder - } - - override fun seedGenerator(): MinimumSeedGenerator { - return theMinSeedGen - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt deleted file mode 100644 index 8c5452575..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class CombinedMinimumBuilder : MinimumBuilder { - private val theSimplexMinimizer: SimplexMinimizer = SimplexMinimizer() - private val theVMMinimizer: VariableMetricMinimizer = VariableMetricMinimizer() - - /** {@inheritDoc} */ - override fun minimum( - fcn: MnFcn?, - gc: GradientCalculator?, - seed: MinimumSeed?, - strategy: MnStrategy?, - maxfcn: Int, - toler: Double - ): FunctionMinimum { - val min: FunctionMinimum = theVMMinimizer.minimize(fcn!!, gc, seed, strategy, maxfcn, toler) - if (!min.isValid()) { - MINUITPlugin.logStatic("CombinedMinimumBuilder: migrad method fails, will try with simplex method first.") - val str = MnStrategy(2) - val min1: FunctionMinimum = theSimplexMinimizer.minimize(fcn, gc, seed, str, maxfcn, toler) - if (!min1.isValid()) { - MINUITPlugin.logStatic("CombinedMinimumBuilder: both migrad and simplex method fail.") - return min1 - } - val seed1: MinimumSeed = theVMMinimizer.seedGenerator().generate(fcn, gc, min1.userState(), str) - val min2: FunctionMinimum = theVMMinimizer.minimize(fcn, gc, seed1, str, maxfcn, toler) - if (!min2.isValid()) { - MINUITPlugin.logStatic("CombinedMinimumBuilder: both migrad and method fails also at 2nd attempt.") - MINUITPlugin.logStatic("CombinedMinimumBuilder: return simplex minimum.") - return min1 - } - return min2 - } - return min - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt b/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt deleted file mode 100644 index 214d94c80..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * ContoursError class. - * - * @author Darksnake - * @version $Id$ - */ -class ContoursError internal constructor( - private val theParX: Int, - private val theParY: Int, - points: List, - xmnos: MinosError, - ymnos: MinosError, - nfcn: Int -) { - private val theNFcn: Int - private val thePoints: List = points - private val theXMinos: MinosError - private val theYMinos: MinosError - - /** - * - * nfcn. - * - * @return a int. - */ - fun nfcn(): Int { - return theNFcn - } - - /** - * - * points. - * - * @return a [List] object. - */ - fun points(): List { - return thePoints - } - - /** - * {@inheritDoc} - */ - override fun toString(): String { - return MnPrint.toString(this) - } - - /** - * - * xMinosError. - * - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun xMinosError(): MinosError { - return theXMinos - } - - /** - * - * xRange. - * - * @return - */ - fun xRange(): Range { - return theXMinos.range() - } - - /** - * - * xmin. - * - * @return a double. - */ - fun xmin(): Double { - return theXMinos.min() - } - - /** - * - * xpar. - * - * @return a int. - */ - fun xpar(): Int { - return theParX - } - - /** - * - * yMinosError. - * - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun yMinosError(): MinosError { - return theYMinos - } - - /** - * - * yRange. - * - * @return - */ - fun yRange(): Range { - return theYMinos.range() - } - - /** - * - * ymin. - * - * @return a double. - */ - fun ymin(): Double { - return theYMinos.min() - } - - /** - * - * ypar. - * - * @return a int. - */ - fun ypar(): Int { - return theParY - } - - init { - theXMinos = xmnos - theYMinos = ymnos - theNFcn = nfcn - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt b/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt deleted file mode 100644 index 9eb2443e4..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -internal class DavidonErrorUpdator : MinimumErrorUpdator { - /** {@inheritDoc} */ - fun update(s0: MinimumState, p1: MinimumParameters, g1: FunctionGradient): MinimumError { - val V0: MnAlgebraicSymMatrix = s0.error().invHessian() - val dx: RealVector = MnUtils.sub(p1.vec(), s0.vec()) - val dg: RealVector = MnUtils.sub(g1.getGradient(), s0.gradient().getGradient()) - val delgam: Double = MnUtils.innerProduct(dx, dg) - val gvg: Double = MnUtils.similarity(dg, V0) - val vg: RealVector = MnUtils.mul(V0, dg) - var Vupd: MnAlgebraicSymMatrix = - MnUtils.sub(MnUtils.div(MnUtils.outerProduct(dx), delgam), MnUtils.div(MnUtils.outerProduct(vg), gvg)) - if (delgam > gvg) { - Vupd = MnUtils.add(Vupd, - MnUtils.mul(MnUtils.outerProduct(MnUtils.sub(MnUtils.div(dx, delgam), MnUtils.div(vg, gvg))), gvg)) - } - val sum_upd: Double = MnUtils.absoluteSumOfElements(Vupd) - Vupd = MnUtils.add(Vupd, V0) - val dcov: Double = 0.5 * (s0.error().dcovar() + sum_upd / MnUtils.absoluteSumOfElements(Vupd)) - return MinimumError(Vupd, dcov) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/FunctionGradient.kt b/kmath-optimization/src/commonMain/tmp/minuit/FunctionGradient.kt deleted file mode 100644 index a0866d916..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/FunctionGradient.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * - * @version $Id$ - */ -class FunctionGradient { - private var theAnalytical = false - private var theG2ndDerivative: RealVector - private var theGStepSize: RealVector - private var theGradient: RealVector - private var theValid = false - - constructor(n: Int) { - theGradient = ArrayRealVector(n) - theG2ndDerivative = ArrayRealVector(n) - theGStepSize = ArrayRealVector(n) - } - - constructor(grd: RealVector) { - theGradient = grd - theG2ndDerivative = ArrayRealVector(grd.getDimension()) - theGStepSize = ArrayRealVector(grd.getDimension()) - theValid = true - theAnalytical = true - } - - constructor(grd: RealVector, g2: RealVector, gstep: RealVector) { - theGradient = grd - theG2ndDerivative = g2 - theGStepSize = gstep - theValid = true - theAnalytical = false - } - - fun getGradient(): RealVector { - return theGradient - } - - fun getGradientDerivative(): RealVector { - return theG2ndDerivative - } - - fun getStep(): RealVector { - return theGStepSize - } - - fun isAnalytical(): Boolean { - return theAnalytical - } - - fun isValid(): Boolean { - return theValid - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt b/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt deleted file mode 100644 index e43523291..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * Result of the minimization. - * - * - * The FunctionMinimum is the output of the minimizers and contains the - * minimization result. The methods - * - * * userState(), - * * userParameters() and - * * userCovariance() - * - * are provided. These can be used as new input to a new minimization after some - * manipulation. The parameters and/or the FunctionMinimum can be printed using - * the toString() method or the MnPrint class. - * - * @author Darksnake - */ -class FunctionMinimum { - private var theAboveMaxEdm = false - private var theErrorDef: Double - private var theReachedCallLimit = false - private var theSeed: MinimumSeed - private var theStates: MutableList - private var theUserState: MnUserParameterState - - internal constructor(seed: MinimumSeed, up: Double) { - theSeed = seed - theStates = ArrayList() - theStates.add(MinimumState(seed.parameters(), - seed.error(), - seed.gradient(), - seed.parameters().fval(), - seed.nfcn())) - theErrorDef = up - theUserState = MnUserParameterState() - } - - internal constructor(seed: MinimumSeed, states: MutableList, up: Double) { - theSeed = seed - theStates = states - theErrorDef = up - theUserState = MnUserParameterState() - } - - internal constructor(seed: MinimumSeed, states: MutableList, up: Double, x: MnReachedCallLimit?) { - theSeed = seed - theStates = states - theErrorDef = up - theReachedCallLimit = true - theUserState = MnUserParameterState() - } - - internal constructor(seed: MinimumSeed, states: MutableList, up: Double, x: MnAboveMaxEdm?) { - theSeed = seed - theStates = states - theErrorDef = up - theAboveMaxEdm = true - theReachedCallLimit = false - theUserState = MnUserParameterState() - } - - // why not - fun add(state: MinimumState) { - theStates.add(state) - } - - /** - * returns the expected vertical distance to the minimum (EDM) - * - * @return a double. - */ - fun edm(): Double { - return lastState().edm() - } - - fun error(): MinimumError { - return lastState().error() - } - - /** - * - * - * errorDef. - * - * @return a double. - */ - fun errorDef(): Double { - return theErrorDef - } - - /** - * Returns the function value at the minimum. - * - * @return a double. - */ - fun fval(): Double { - return lastState().fval() - } - - fun grad(): FunctionGradient { - return lastState().gradient() - } - - fun hasAccurateCovar(): Boolean { - return state().error().isAccurate() - } - - fun hasCovariance(): Boolean { - return state().error().isAvailable() - } - - fun hasMadePosDefCovar(): Boolean { - return state().error().isMadePosDef() - } - - fun hasPosDefCovar(): Boolean { - return state().error().isPosDef() - } - - fun hasReachedCallLimit(): Boolean { - return theReachedCallLimit - } - - fun hasValidCovariance(): Boolean { - return state().error().isValid() - } - - fun hasValidParameters(): Boolean { - return state().parameters().isValid() - } - - fun hesseFailed(): Boolean { - return state().error().hesseFailed() - } - - fun isAboveMaxEdm(): Boolean { - return theAboveMaxEdm - } - - /** - * In general, if this returns true, the minimizer did find a - * minimum without running into troubles. However, in some cases a minimum - * cannot be found, then the return value will be false. - * Reasons for the minimization to fail are - * - * * the number of allowed function calls has been exhausted - * * the minimizer could not improve the values of the parameters (and - * knowing that it has not converged yet) - * * a problem with the calculation of the covariance matrix - * - * Additional methods for the analysis of the state at the minimum are - * provided. - * - * @return a boolean. - */ - fun isValid(): Boolean { - return state().isValid() && !isAboveMaxEdm() && !hasReachedCallLimit() - } - - private fun lastState(): MinimumState { - return theStates[theStates.size - 1] - } - // forward interface of last state - /** - * returns the total number of function calls during the minimization. - * - * @return a int. - */ - fun nfcn(): Int { - return lastState().nfcn() - } - - fun parameters(): MinimumParameters { - return lastState().parameters() - } - - fun seed(): MinimumSeed { - return theSeed - } - - fun state(): MinimumState { - return lastState() - } - - fun states(): List { - return theStates - } - - /** - * {@inheritDoc} - * - * @return - */ - override fun toString(): String { - return MnPrint.toString(this) - } - - /** - * - * - * userCovariance. - * - * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun userCovariance(): MnUserCovariance { - if (!theUserState.isValid()) { - theUserState = MnUserParameterState(state(), errorDef(), seed().trafo()) - } - return theUserState.covariance() - } - - /** - * - * - * userParameters. - * - * @return a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - fun userParameters(): MnUserParameters { - if (!theUserState.isValid()) { - theUserState = MnUserParameterState(state(), errorDef(), seed().trafo()) - } - return theUserState.parameters() - } - - /** - * user representation of state at minimum - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun userState(): MnUserParameterState { - if (!theUserState.isValid()) { - theUserState = MnUserParameterState(state(), errorDef(), seed().trafo()) - } - return theUserState - } - - internal class MnAboveMaxEdm - internal class MnReachedCallLimit -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/GradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/GradientCalculator.kt deleted file mode 100644 index 379de1b6d..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/GradientCalculator.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -interface GradientCalculator { - /** - * - * gradient. - * - * @param par a [hep.dataforge.MINUIT.MinimumParameters] object. - * @return a [hep.dataforge.MINUIT.FunctionGradient] object. - */ - fun gradient(par: MinimumParameters?): FunctionGradient - - /** - * - * gradient. - * - * @param par a [hep.dataforge.MINUIT.MinimumParameters] object. - * @param grad a [hep.dataforge.MINUIT.FunctionGradient] object. - * @return a [hep.dataforge.MINUIT.FunctionGradient] object. - */ - fun gradient(par: MinimumParameters?, grad: FunctionGradient?): FunctionGradient -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/HessianGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/HessianGradientCalculator.kt deleted file mode 100644 index 4ef743955..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/HessianGradientCalculator.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -internal class HessianGradientCalculator(fcn: MnFcn, par: MnUserTransformation, stra: MnStrategy) : GradientCalculator { - private val theFcn: MnFcn = fcn - private val theStrategy: MnStrategy - private val theTransformation: MnUserTransformation - fun deltaGradient(par: MinimumParameters, gradient: FunctionGradient): Pair { - require(par.isValid()) { "parameters are invalid" } - val x: RealVector = par.vec().copy() - val grd: RealVector = gradient.getGradient().copy() - val g2: RealVector = gradient.getGradientDerivative() - val gstep: RealVector = gradient.getStep() - val fcnmin: Double = par.fval() - // standardDiviation::cout<<"fval: "< optstp) { - d = optstp - } - if (d < dmin) { - d = dmin - } - var chgold = 10000.0 - var dgmin = 0.0 - var grdold = 0.0 - var grdnew = 0.0 - for (j in 0 until ncycle()) { - x.setEntry(i, xtf + d) - val fs1: Double = theFcn.value(x) - x.setEntry(i, xtf - d) - val fs2: Double = theFcn.value(x) - x.setEntry(i, xtf) - // double sag = 0.5*(fs1+fs2-2.*fcnmin); - grdold = grd.getEntry(i) - grdnew = (fs1 - fs2) / (2.0 * d) - dgmin = precision().eps() * (abs(fs1) + abs(fs2)) / d - if (abs(grdnew) < precision().eps()) { - break - } - val change: Double = abs((grdold - grdnew) / grdnew) - if (change > chgold && j > 1) { - break - } - chgold = change - grd.setEntry(i, grdnew) - if (change < 0.05) { - break - } - if (abs(grdold - grdnew) < dgmin) { - break - } - if (d < dmin) { - break - } - d *= 0.2 - } - dgrd.setEntry(i, max(dgmin, abs(grdold - grdnew))) - } - return Pair(FunctionGradient(grd, g2, gstep), dgrd) - } - - fun fcn(): MnFcn { - return theFcn - } - - fun gradTolerance(): Double { - return strategy().gradientTolerance() - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters): FunctionGradient { - val gc = InitialGradientCalculator(theFcn, theTransformation, theStrategy) - val gra: FunctionGradient = gc.gradient(par) - return gradient(par, gra) - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters, gradient: FunctionGradient): FunctionGradient { - return deltaGradient(par, gradient).getFirst() - } - - fun ncycle(): Int { - return strategy().hessianGradientNCycles() - } - - fun precision(): MnMachinePrecision { - return theTransformation.precision() - } - - fun stepTolerance(): Double { - return strategy().gradientStepTolerance() - } - - fun strategy(): MnStrategy { - return theStrategy - } - - fun trafo(): MnUserTransformation { - return theTransformation - } - - init { - theTransformation = par - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/InitialGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/InitialGradientCalculator.kt deleted file mode 100644 index 794556414..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/InitialGradientCalculator.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* - -/** - * Calculating derivatives via finite differences - * @version $Id$ - */ -internal class InitialGradientCalculator(fcn: MnFcn, par: MnUserTransformation, stra: MnStrategy) { - private val theFcn: MnFcn = fcn - private val theStrategy: MnStrategy - private val theTransformation: MnUserTransformation - fun fcn(): MnFcn { - return theFcn - } - - fun gradTolerance(): Double { - return strategy().gradientTolerance() - } - - fun gradient(par: MinimumParameters): FunctionGradient { - require(par.isValid()) { "Parameters are invalid" } - val n: Int = trafo().variableParameters() - require(n == par.vec().getDimension()) { "Parameters have invalid size" } - val gr: RealVector = ArrayRealVector(n) - val gr2: RealVector = ArrayRealVector(n) - val gst: RealVector = ArrayRealVector(n) - - // initial starting values - for (i in 0 until n) { - val exOfIn: Int = trafo().extOfInt(i) - val `var`: Double = par.vec().getEntry(i) //parameter value - val werr: Double = trafo().parameter(exOfIn).error() //parameter error - val sav: Double = trafo().int2ext(i, `var`) //value after transformation - var sav2 = sav + werr //value after transfomation + error - if (trafo().parameter(exOfIn).hasLimits()) { - if (trafo().parameter(exOfIn).hasUpperLimit() - && sav2 > trafo().parameter(exOfIn).upperLimit() - ) { - sav2 = trafo().parameter(exOfIn).upperLimit() - } - } - var var2: Double = trafo().ext2int(exOfIn, sav2) - val vplu = var2 - `var` - sav2 = sav - werr - if (trafo().parameter(exOfIn).hasLimits()) { - if (trafo().parameter(exOfIn).hasLowerLimit() - && sav2 < trafo().parameter(exOfIn).lowerLimit() - ) { - sav2 = trafo().parameter(exOfIn).lowerLimit() - } - } - var2 = trafo().ext2int(exOfIn, sav2) - val vmin = var2 - `var` - val dirin: Double = 0.5 * (abs(vplu) + abs(vmin)) - val g2: Double = 2.0 * theFcn.errorDef() / (dirin * dirin) - val gsmin: Double = 8.0 * precision().eps2() * (abs(`var`) + precision().eps2()) - var gstep: Double = max(gsmin, 0.1 * dirin) - val grd = g2 * dirin - if (trafo().parameter(exOfIn).hasLimits()) { - if (gstep > 0.5) { - gstep = 0.5 - } - } - gr.setEntry(i, grd) - gr2.setEntry(i, g2) - gst.setEntry(i, gstep) - } - return FunctionGradient(gr, gr2, gst) - } - - fun gradient(par: MinimumParameters, gra: FunctionGradient?): FunctionGradient { - return gradient(par) - } - - fun ncycle(): Int { - return strategy().gradientNCycles() - } - - fun precision(): MnMachinePrecision { - return theTransformation.precision() - } - - fun stepTolerance(): Double { - return strategy().gradientStepTolerance() - } - - fun strategy(): MnStrategy { - return theStrategy - } - - fun trafo(): MnUserTransformation { - return theTransformation - } - - init { - theTransformation = par - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINOSResult.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINOSResult.kt deleted file mode 100644 index c33994648..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MINOSResult.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package space.kscience.kmath.optimization.minuit - - -/** - * Контейнер для несимметричных оценок и доверительных интервалов - * - * @author Darksnake - * @version $Id: $Id - */ -class MINOSResult -/** - * - * Constructor for MINOSResult. - * - * @param list an array of [String] objects. - */(private val names: Array, private val errl: DoubleArray?, private val errp: DoubleArray?) : - IntervalEstimate { - fun getNames(): NameList { - return NameList(names) - } - - fun getInterval(parName: String?): Pair { - val index: Int = getNames().getNumberByName(parName) - return Pair(ValueFactory.of(errl!![index]), ValueFactory.of(errp!![index])) - } - - val cL: Double - get() = 0.68 - - /** {@inheritDoc} */ - fun print(out: PrintWriter) { - if (errl != null || errp != null) { - out.println() - out.println("Assymetrical errors:") - out.println() - out.println("Name\tLower\tUpper") - for (i in 0 until getNames().size()) { - out.print(getNames().get(i)) - out.print("\t") - if (errl != null) { - out.print(errl[i]) - } else { - out.print("---") - } - out.print("\t") - if (errp != null) { - out.print(errp[i]) - } else { - out.print("---") - } - out.println() - } - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt deleted file mode 100644 index a26321249..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -package space.kscience.kmath.optimization.minuit - -import ru.inr.mass.minuit.* - -/** - * - * - * MINUITFitter class. - * - * @author Darksnake - * @version $Id: $Id - */ -class MINUITFitter : Fitter { - fun run(state: FitState, parentLog: History?, meta: Meta): FitResult { - val log = Chronicle("MINUIT", parentLog) - val action: String = meta.getString("action", TASK_RUN) - log.report("MINUIT fit engine started action '{}'", action) - return when (action) { - TASK_COVARIANCE -> runHesse(state, log, meta) - TASK_SINGLE, TASK_RUN -> runFit(state, log, meta) - else -> throw IllegalArgumentException("Unknown task") - } - } - - @NotNull - fun getName(): String { - return MINUIT_ENGINE_NAME - } - - /** - * - * - * runHesse. - * - * @param state a [hep.dataforge.stat.fit.FitState] object. - * @param log - * @return a [FitResult] object. - */ - fun runHesse(state: FitState, log: History, meta: Meta?): FitResult { - val strategy: Int - strategy = Global.INSTANCE.getInt("MINUIT_STRATEGY", 2) - log.report("Generating errors using MnHesse 2-nd order gradient calculator.") - val fcn: MultiFunction - val fitPars: Array = Fitter.Companion.getFitPars(state, meta) - val pars: ParamSet = state.getParameters() - fcn = MINUITUtils.getFcn(state, pars, fitPars) - val hesse = MnHesse(strategy) - val mnState: MnUserParameterState = hesse.calculate(fcn, MINUITUtils.getFitParameters(pars, fitPars)) - val allPars: ParamSet = pars.copy() - for (fitPar in fitPars) { - allPars.setParValue(fitPar, mnState.value(fitPar)) - allPars.setParError(fitPar, mnState.error(fitPar)) - } - val newState: FitState.Builder = state.edit() - newState.setPars(allPars) - if (mnState.hasCovariance()) { - val mnCov: MnUserCovariance = mnState.covariance() - var j: Int - val cov = Array(mnState.variableParameters()) { DoubleArray(mnState.variableParameters()) } - for (i in 0 until mnState.variableParameters()) { - j = 0 - while (j < mnState.variableParameters()) { - cov[i][j] = mnCov.get(i, j) - j++ - } - } - newState.setCovariance(NamedMatrix(fitPars, cov), true) - } - return FitResult.build(newState.build(), fitPars) - } - - fun runFit(state: FitState, log: History, meta: Meta): FitResult { - val minuit: MnApplication - log.report("Starting fit using Minuit.") - val strategy: Int - strategy = Global.INSTANCE.getInt("MINUIT_STRATEGY", 2) - var force: Boolean - force = Global.INSTANCE.getBoolean("FORCE_DERIVS", false) - val fitPars: Array = Fitter.Companion.getFitPars(state, meta) - for (fitPar in fitPars) { - if (!state.modelProvidesDerivs(fitPar)) { - force = true - log.reportError("Model does not provide derivatives for parameter '{}'", fitPar) - } - } - if (force) { - log.report("Using MINUIT gradient calculator.") - } - val fcn: MultiFunction - val pars: ParamSet = state.getParameters().copy() - fcn = MINUITUtils.getFcn(state, pars, fitPars) - val method: String = meta.getString("method", MINUIT_MIGRAD) - when (method) { - MINUIT_MINOS, MINUIT_MINIMIZE -> minuit = - MnMinimize(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy) - MINUIT_SIMPLEX -> minuit = MnSimplex(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy) - else -> minuit = MnMigrad(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy) - } - if (force) { - minuit.setUseAnalyticalDerivatives(false) - log.report("Forced to use MINUIT internal derivative calculator!") - } - -// minuit.setUseAnalyticalDerivatives(true); - val minimum: FunctionMinimum - val maxSteps: Int = meta.getInt("iterations", -1) - val tolerance: Double = meta.getDouble("tolerance", -1) - minimum = if (maxSteps > 0) { - if (tolerance > 0) { - minuit.minimize(maxSteps, tolerance) - } else { - minuit.minimize(maxSteps) - } - } else { - minuit.minimize() - } - if (!minimum.isValid()) { - log.report("Minimization failed!") - } - log.report("MINUIT run completed in {} function calls.", minimum.nfcn()) - - /* - * Генерация результата - */ - val allPars: ParamSet = pars.copy() - for (fitPar in fitPars) { - allPars.setParValue(fitPar, minimum.userParameters().value(fitPar)) - allPars.setParError(fitPar, minimum.userParameters().error(fitPar)) - } - val newState: FitState.Builder = state.edit() - newState.setPars(allPars) - var valid: Boolean = minimum.isValid() - if (minimum.userCovariance().nrow() > 0) { - var j: Int - val cov = Array(minuit.variableParameters()) { DoubleArray(minuit.variableParameters()) } - if (cov[0].length == 1) { - cov[0][0] = minimum.userParameters().error(0) * minimum.userParameters().error(0) - } else { - for (i in 0 until minuit.variableParameters()) { - j = 0 - while (j < minuit.variableParameters()) { - cov[i][j] = minimum.userCovariance().get(i, j) - j++ - } - } - } - newState.setCovariance(NamedMatrix(fitPars, cov), true) - } - if (method == MINUIT_MINOS) { - log.report("Starting MINOS procedure for precise error estimation.") - val minos = MnMinos(fcn, minimum, strategy) - var mnError: MinosError - val errl = DoubleArray(fitPars.size) - val errp = DoubleArray(fitPars.size) - for (i in fitPars.indices) { - mnError = minos.minos(i) - if (mnError.isValid()) { - errl[i] = mnError.lower() - errp[i] = mnError.upper() - } else { - valid = false - } - } - val minosErrors = MINOSResult(fitPars, errl, errp) - newState.setInterval(minosErrors) - } - return FitResult.build(newState.build(), valid, fitPars) - } - - companion object { - /** - * Constant `MINUIT_MIGRAD="MIGRAD"` - */ - const val MINUIT_MIGRAD = "MIGRAD" - - /** - * Constant `MINUIT_MINIMIZE="MINIMIZE"` - */ - const val MINUIT_MINIMIZE = "MINIMIZE" - - /** - * Constant `MINUIT_SIMPLEX="SIMPLEX"` - */ - const val MINUIT_SIMPLEX = "SIMPLEX" - - /** - * Constant `MINUIT_MINOS="MINOS"` - */ - const val MINUIT_MINOS = "MINOS" //MINOS errors - - /** - * Constant `MINUIT_HESSE="HESSE"` - */ - const val MINUIT_HESSE = "HESSE" //HESSE errors - - /** - * Constant `MINUIT_ENGINE_NAME="MINUIT"` - */ - const val MINUIT_ENGINE_NAME = "MINUIT" - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt deleted file mode 100644 index 7eaefd9d2..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -package space.kscience.kmath.optimization.minuit - -import hep.dataforge.context.* - -/** - * Мэнеджер для MINUITа. Пока не играет никакой активной роли кроме ведения - * внутреннего лога. - * - * @author Darksnake - * @version $Id: $Id - */ -@PluginDef(group = "hep.dataforge", - name = "MINUIT", - dependsOn = ["hep.dataforge:fitting"], - info = "The MINUIT fitter engine for DataForge fitting") -class MINUITPlugin : BasicPlugin() { - fun attach(@NotNull context: Context?) { - super.attach(context) - clearStaticLog() - } - - @Provides(Fitter.FITTER_TARGET) - fun getFitter(fitterName: String): Fitter? { - return if (fitterName == "MINUIT") { - MINUITFitter() - } else { - null - } - } - - @ProvidesNames(Fitter.FITTER_TARGET) - fun listFitters(): List { - return listOf("MINUIT") - } - - fun detach() { - clearStaticLog() - super.detach() - } - - class Factory : PluginFactory() { - fun build(meta: Meta?): Plugin { - return MINUITPlugin() - } - - fun getType(): java.lang.Class { - return MINUITPlugin::class.java - } - } - - companion object { - /** - * Constant `staticLog` - */ - private val staticLog: Chronicle? = Chronicle("MINUIT-STATIC", Global.INSTANCE.getHistory()) - - /** - * - * - * clearStaticLog. - */ - fun clearStaticLog() { - staticLog.clear() - } - - /** - * - * - * logStatic. - * - * @param str a [String] object. - * @param pars a [Object] object. - */ - fun logStatic(str: String?, vararg pars: Any?) { - checkNotNull(staticLog) { "MINUIT log is not initialized." } - staticLog.report(str, pars) - LoggerFactory.getLogger("MINUIT").info(String.format(str, *pars)) - // Out.out.printf(str,pars); -// Out.out.println(); - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINUITUtils.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITUtils.kt deleted file mode 100644 index 44c70cb42..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MINUITUtils.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -package space.kscience.kmath.optimization.minuit - -import hep.dataforge.MINUIT.FunctionMinimum - -internal object MINUITUtils { - fun getFcn(source: FitState, allPar: ParamSet, fitPars: Array): MultiFunction { - return MnFunc(source, allPar, fitPars) - } - - fun getFitParameters(set: ParamSet, fitPars: Array): MnUserParameters { - val pars = MnUserParameters() - var i: Int - var par: Param - i = 0 - while (i < fitPars.size) { - par = set.getByName(fitPars[i]) - pars.add(fitPars[i], par.getValue(), par.getErr()) - if (par.getLowerBound() > Double.NEGATIVE_INFINITY && par.getUpperBound() < Double.POSITIVE_INFINITY) { - pars.setLimits(i, par.getLowerBound(), par.getUpperBound()) - } else if (par.getLowerBound() > Double.NEGATIVE_INFINITY) { - pars.setLowerLimit(i, par.getLowerBound()) - } else if (par.getUpperBound() < Double.POSITIVE_INFINITY) { - pars.setUpperLimit(i, par.getUpperBound()) - } - i++ - } - return pars - } - - fun getValueSet(allPar: ParamSet, names: Array, values: DoubleArray): ParamSet { - assert(values.size == names.size) - assert(allPar.getNames().contains(names)) - val vector: ParamSet = allPar.copy() - for (i in values.indices) { - vector.setParValue(names[i], values[i]) - } - return vector - } - - fun isValidArray(ar: DoubleArray): Boolean { - for (i in ar.indices) { - if (java.lang.Double.isNaN(ar[i])) { - return false - } - } - return true - } - - /** - * - * - * printMINUITResult. - * - * @param out a [PrintWriter] object. - * @param minimum a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun printMINUITResult(out: PrintWriter, minimum: FunctionMinimum?) { - out.println() - out.println("***MINUIT INTERNAL FIT INFORMATION***") - out.println() - MnPrint.print(out, minimum) - out.println() - out.println("***END OF MINUIT INTERNAL FIT INFORMATION***") - out.println() - } - - internal class MnFunc(source: FitState, allPar: ParamSet, fitPars: Array) : MultiFunction { - var source: FitState - var allPar: ParamSet - var fitPars: Array - fun value(doubles: DoubleArray): Double { - assert(isValidArray(doubles)) - assert(doubles.size == fitPars.size) - return -2 * source.getLogProb(getValueSet(allPar, fitPars, doubles)) - // source.getChi2(getValueSet(allPar, fitPars, doubles)); - } - - @Throws(NotDefinedException::class) - fun derivValue(n: Int, doubles: DoubleArray): Double { - assert(isValidArray(doubles)) - assert(doubles.size == getDimension()) - val set: ParamSet = getValueSet(allPar, fitPars, doubles) - -// double res; -// double d, s, deriv; -// -// res = 0; -// for (int i = 0; i < source.getDataNum(); i++) { -// d = source.getDis(i, set); -// s = source.getDispersion(i, set); -// if (source.modelProvidesDerivs(fitPars[n])) { -// deriv = source.getDisDeriv(fitPars[n], i, set); -// } else { -// throw new NotDefinedException(); -// // Такого не должно быть, поскольку мы где-то наверху должы были проверить, что производные все есть. -// } -// res += 2 * d * deriv / s; -// } - return -2 * source.getLogProbDeriv(fitPars[n], set) - } - - fun getDimension(): Int { - return fitPars.size - } - - fun providesDeriv(n: Int): Boolean { - return source.modelProvidesDerivs(fitPars[n]) - } - - init { - this.source = source - this.allPar = allPar - this.fitPars = fitPars - assert(source.getModel().getNames().contains(fitPars)) - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt deleted file mode 100644 index 7d918c339..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -interface MinimumBuilder { - /** - * - * minimum. - * - * @param fcn a [hep.dataforge.MINUIT.MnFcn] object. - * @param gc a [hep.dataforge.MINUIT.GradientCalculator] object. - * @param seed a [hep.dataforge.MINUIT.MinimumSeed] object. - * @param strategy a [hep.dataforge.MINUIT.MnStrategy] object. - * @param maxfcn a int. - * @param toler a double. - * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun minimum( - fcn: MnFcn?, - gc: GradientCalculator?, - seed: MinimumSeed?, - strategy: MnStrategy?, - maxfcn: Int, - toler: Double - ): FunctionMinimum -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumError.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumError.kt deleted file mode 100644 index 6993b9e6d..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumError.kt +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin - -/** - * MinimumError keeps the inverse 2nd derivative (inverse Hessian) used for - * calculating the parameter step size (-V*g) and for the covariance update - * (ErrorUpdator). The covariance matrix is equal to twice the inverse Hessian. - * - * @version $Id$ - */ -class MinimumError { - private var theAvailable = false - private var theDCovar: Double - private var theHesseFailed = false - private var theInvertFailed = false - private var theMadePosDef = false - private var theMatrix: MnAlgebraicSymMatrix - private var thePosDef = false - private var theValid = false - - constructor(n: Int) { - theMatrix = MnAlgebraicSymMatrix(n) - theDCovar = 1.0 - } - - constructor(mat: MnAlgebraicSymMatrix, dcov: Double) { - theMatrix = mat - theDCovar = dcov - theValid = true - thePosDef = true - theAvailable = true - } - - constructor(mat: MnAlgebraicSymMatrix, x: MnHesseFailed?) { - theMatrix = mat - theDCovar = 1.0 - theValid = false - thePosDef = false - theMadePosDef = false - theHesseFailed = true - theInvertFailed = false - theAvailable = true - } - - constructor(mat: MnAlgebraicSymMatrix, x: MnMadePosDef?) { - theMatrix = mat - theDCovar = 1.0 - theValid = false - thePosDef = false - theMadePosDef = true - theHesseFailed = false - theInvertFailed = false - theAvailable = true - } - - constructor(mat: MnAlgebraicSymMatrix, x: MnInvertFailed?) { - theMatrix = mat - theDCovar = 1.0 - theValid = false - thePosDef = true - theMadePosDef = false - theHesseFailed = false - theInvertFailed = true - theAvailable = true - } - - constructor(mat: MnAlgebraicSymMatrix, x: MnNotPosDef?) { - theMatrix = mat - theDCovar = 1.0 - theValid = false - thePosDef = false - theMadePosDef = false - theHesseFailed = false - theInvertFailed = false - theAvailable = true - } - - fun dcovar(): Double { - return theDCovar - } - - fun hesseFailed(): Boolean { - return theHesseFailed - } - - fun hessian(): MnAlgebraicSymMatrix { - return try { - val tmp: MnAlgebraicSymMatrix = theMatrix.copy() - tmp.invert() - tmp - } catch (x: SingularMatrixException) { - MINUITPlugin.logStatic("BasicMinimumError inversion fails; return diagonal matrix.") - val tmp = MnAlgebraicSymMatrix(theMatrix.nrow()) - var i = 0 - while (i < theMatrix.nrow()) { - tmp[i, i] = 1.0 / theMatrix[i, i] - i++ - } - tmp - } - } - - fun invHessian(): MnAlgebraicSymMatrix { - return theMatrix - } - - fun invertFailed(): Boolean { - return theInvertFailed - } - - fun isAccurate(): Boolean { - return theDCovar < 0.1 - } - - fun isAvailable(): Boolean { - return theAvailable - } - - fun isMadePosDef(): Boolean { - return theMadePosDef - } - - fun isPosDef(): Boolean { - return thePosDef - } - - fun isValid(): Boolean { - return theValid - } - - fun matrix(): MnAlgebraicSymMatrix { - return MnUtils.mul(theMatrix, 2) - } - - internal class MnHesseFailed - internal class MnInvertFailed - internal class MnMadePosDef - internal class MnNotPosDef -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt deleted file mode 100644 index 6022aa5b7..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal interface MinimumErrorUpdator { - /** - * - * update. - * - * @param state a [hep.dataforge.MINUIT.MinimumState] object. - * @param par a [hep.dataforge.MINUIT.MinimumParameters] object. - * @param grad a [hep.dataforge.MINUIT.FunctionGradient] object. - * @return a [hep.dataforge.MINUIT.MinimumError] object. - */ - fun update(state: MinimumState?, par: MinimumParameters?, grad: FunctionGradient?): MinimumError? -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumParameters.kt deleted file mode 100644 index bed13ea0b..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumParameters.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * - * @version $Id$ - */ -class MinimumParameters { - private var theFVal = 0.0 - private var theHasStep = false - private var theParameters: RealVector - private var theStepSize: RealVector - private var theValid = false - - constructor(n: Int) { - theParameters = ArrayRealVector(n) - theStepSize = ArrayRealVector(n) - } - - constructor(avec: RealVector, fval: Double) { - theParameters = avec - theStepSize = ArrayRealVector(avec.getDimension()) - theFVal = fval - theValid = true - } - - constructor(avec: RealVector, dirin: RealVector, fval: Double) { - theParameters = avec - theStepSize = dirin - theFVal = fval - theValid = true - theHasStep = true - } - - fun dirin(): RealVector { - return theStepSize - } - - fun fval(): Double { - return theFVal - } - - fun hasStepSize(): Boolean { - return theHasStep - } - - fun isValid(): Boolean { - return theValid - } - - fun vec(): RealVector { - return theParameters - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeed.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeed.kt deleted file mode 100644 index 53a78da75..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeed.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package space.kscience.kmath.optimization.minuit - -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -class MinimumSeed(state: MinimumState, trafo: MnUserTransformation) { - private val theState: MinimumState = state - private val theTrafo: MnUserTransformation = trafo - private val theValid: Boolean = true - val edm: Double get() = state().edm() - - fun error(): MinimumError { - return state().error() - } - - fun fval(): Double { - return state().fval() - } - - fun gradient(): FunctionGradient { - return state().gradient() - } - - fun isValid(): Boolean { - return theValid - } - - fun nfcn(): Int { - return state().nfcn() - } - - fun parameters(): MinimumParameters { - return state().parameters() - } - - fun precision(): MnMachinePrecision { - return theTrafo.precision() - } - - fun state(): MinimumState { - return theState - } - - fun trafo(): MnUserTransformation { - return theTrafo - } - -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt deleted file mode 100644 index e152559b5..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * base class for seed generators (starting values); the seed generator prepares - * initial starting values from the input (MnUserParameterState) for the - * minimization; - * - * @version $Id$ - */ -interface MinimumSeedGenerator { - /** - * - * generate. - * - * @param fcn a [hep.dataforge.MINUIT.MnFcn] object. - * @param calc a [hep.dataforge.MINUIT.GradientCalculator] object. - * @param user a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. - * @return a [hep.dataforge.MINUIT.MinimumSeed] object. - */ - fun generate(fcn: MnFcn?, calc: GradientCalculator?, user: MnUserParameterState?, stra: MnStrategy?): MinimumSeed -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumState.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumState.kt deleted file mode 100644 index 9f63e0e1f..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumState.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector - -/** - * MinimumState keeps the information (position, gradient, 2nd deriv, etc) after - * one minimization step (usually in MinimumBuilder). - * - * @version $Id$ - */ -class MinimumState { - private var theEDM = 0.0 - private var theError: MinimumError - private var theGradient: FunctionGradient - private var theNFcn = 0 - private var theParameters: MinimumParameters - - constructor(n: Int) { - theParameters = MinimumParameters(n) - theError = MinimumError(n) - theGradient = FunctionGradient(n) - } - - constructor(states: MinimumParameters, err: MinimumError, grad: FunctionGradient, edm: Double, nfcn: Int) { - theParameters = states - theError = err - theGradient = grad - theEDM = edm - theNFcn = nfcn - } - - constructor(states: MinimumParameters, edm: Double, nfcn: Int) { - theParameters = states - theError = MinimumError(states.vec().getDimension()) - theGradient = FunctionGradient(states.vec().getDimension()) - theEDM = edm - theNFcn = nfcn - } - - fun edm(): Double { - return theEDM - } - - fun error(): MinimumError { - return theError - } - - fun fval(): Double { - return theParameters.fval() - } - - fun gradient(): FunctionGradient { - return theGradient - } - - fun hasCovariance(): Boolean { - return theError.isAvailable() - } - - fun hasParameters(): Boolean { - return theParameters.isValid() - } - - fun isValid(): Boolean { - return if (hasParameters() && hasCovariance()) { - parameters().isValid() && error().isValid() - } else if (hasParameters()) { - parameters().isValid() - } else { - false - } - } - - fun nfcn(): Int { - return theNFcn - } - - fun parameters(): MinimumParameters { - return theParameters - } - - fun size(): Int { - return theParameters.vec().getDimension() - } - - fun vec(): RealVector { - return theParameters.vec() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinosError.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinosError.kt deleted file mode 100644 index c7cf10523..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinosError.kt +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * MinosError class. - * - * @author Darksnake - * @version $Id$ - */ -class MinosError { - private var theLower: MnCross - private var theMinValue = 0.0 - private var theParameter = 0 - private var theUpper: MnCross - - internal constructor() { - theUpper = MnCross() - theLower = MnCross() - } - - internal constructor(par: Int, min: Double, low: MnCross, up: MnCross) { - theParameter = par - theMinValue = min - theUpper = up - theLower = low - } - - /** - * - * atLowerLimit. - * - * @return a boolean. - */ - fun atLowerLimit(): Boolean { - return theLower.atLimit() - } - - /** - * - * atLowerMaxFcn. - * - * @return a boolean. - */ - fun atLowerMaxFcn(): Boolean { - return theLower.atMaxFcn() - } - - /** - * - * atUpperLimit. - * - * @return a boolean. - */ - fun atUpperLimit(): Boolean { - return theUpper.atLimit() - } - - /** - * - * atUpperMaxFcn. - * - * @return a boolean. - */ - fun atUpperMaxFcn(): Boolean { - return theUpper.atMaxFcn() - } - - /** - * - * isValid. - * - * @return a boolean. - */ - fun isValid(): Boolean { - return theLower.isValid() && theUpper.isValid() - } - - /** - * - * lower. - * - * @return a double. - */ - fun lower(): Double { - return -1.0 * lowerState().error(parameter()) * (1.0 + theLower.value()) - } - - /** - * - * lowerNewMin. - * - * @return a boolean. - */ - fun lowerNewMin(): Boolean { - return theLower.newMinimum() - } - - /** - * - * lowerState. - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun lowerState(): MnUserParameterState { - return theLower.state() - } - - /** - * - * lowerValid. - * - * @return a boolean. - */ - fun lowerValid(): Boolean { - return theLower.isValid() - } - - /** - * - * min. - * - * @return a double. - */ - fun min(): Double { - return theMinValue - } - - /** - * - * nfcn. - * - * @return a int. - */ - fun nfcn(): Int { - return theUpper.nfcn() + theLower.nfcn() - } - - /** - * - * parameter. - * - * @return a int. - */ - fun parameter(): Int { - return theParameter - } - - /** - * - * range. - * - * @return - */ - fun range(): Range { - return Range(lower(), upper()) - } - - /** - * {@inheritDoc} - */ - override fun toString(): String { - return MnPrint.toString(this) - } - - /** - * - * upper. - * - * @return a double. - */ - fun upper(): Double { - return upperState().error(parameter()) * (1.0 + theUpper.value()) - } - - /** - * - * upperNewMin. - * - * @return a boolean. - */ - fun upperNewMin(): Boolean { - return theUpper.newMinimum() - } - - /** - * - * upperState. - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun upperState(): MnUserParameterState { - return theUpper.state() - } - - /** - * - * upperValid. - * - * @return a boolean. - */ - fun upperValid(): Boolean { - return theUpper.isValid() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt deleted file mode 100644 index ff6834df4..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -class MinuitParameter { - private var theConst = false - private var theError = 0.0 - private var theFix = false - private var theLoLimValid = false - private var theLoLimit = 0.0 - private var theName: String - private var theNum: Int - private var theUpLimValid = false - private var theUpLimit = 0.0 - private var theValue: Double - - /** - * constructor for constant parameter - * - * @param num a int. - * @param name a [String] object. - * @param val a double. - */ - constructor(num: Int, name: String, `val`: Double) { - theNum = num - theValue = `val` - theConst = true - theName = name - } - - /** - * constructor for standard parameter - * - * @param num a int. - * @param name a [String] object. - * @param val a double. - * @param err a double. - */ - constructor(num: Int, name: String, `val`: Double, err: Double) { - theNum = num - theValue = `val` - theError = err - theName = name - } - - /** - * constructor for limited parameter - * - * @param num a int. - * @param name a [String] object. - * @param val a double. - * @param err a double. - * @param min a double. - * @param max a double. - */ - constructor(num: Int, name: String, `val`: Double, err: Double, min: Double, max: Double) { - theNum = num - theValue = `val` - theError = err - theLoLimit = min - theUpLimit = max - theLoLimValid = true - theUpLimValid = true - require(min != max) { "min == max" } - if (min > max) { - theLoLimit = max - theUpLimit = min - } - theName = name - } - - private constructor(other: MinuitParameter) { - theNum = other.theNum - theName = other.theName - theValue = other.theValue - theError = other.theError - theConst = other.theConst - theFix = other.theFix - theLoLimit = other.theLoLimit - theUpLimit = other.theUpLimit - theLoLimValid = other.theLoLimValid - theUpLimValid = other.theUpLimValid - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MinuitParameter] object. - */ - fun copy(): MinuitParameter { - return MinuitParameter(this) - } - - /** - * - * error. - * - * @return a double. - */ - fun error(): Double { - return theError - } - - /** - * - * fix. - */ - fun fix() { - theFix = true - } - - /** - * - * hasLimits. - * - * @return a boolean. - */ - fun hasLimits(): Boolean { - return theLoLimValid || theUpLimValid - } - - /** - * - * hasLowerLimit. - * - * @return a boolean. - */ - fun hasLowerLimit(): Boolean { - return theLoLimValid - } - - /** - * - * hasUpperLimit. - * - * @return a boolean. - */ - fun hasUpperLimit(): Boolean { - return theUpLimValid - } - //state of parameter (fixed/const/limited) - /** - * - * isConst. - * - * @return a boolean. - */ - fun isConst(): Boolean { - return theConst - } - - /** - * - * isFixed. - * - * @return a boolean. - */ - fun isFixed(): Boolean { - return theFix - } - - /** - * - * lowerLimit. - * - * @return a double. - */ - fun lowerLimit(): Double { - return theLoLimit - } - - /** - * - * name. - * - * @return a [String] object. - */ - fun name(): String { - return theName - } - //access methods - /** - * - * number. - * - * @return a int. - */ - fun number(): Int { - return theNum - } - - /** - * - * release. - */ - fun release() { - theFix = false - } - - /** - * - * removeLimits. - */ - fun removeLimits() { - theLoLimit = 0.0 - theUpLimit = 0.0 - theLoLimValid = false - theUpLimValid = false - } - - /** - * - * setError. - * - * @param err a double. - */ - fun setError(err: Double) { - theError = err - theConst = false - } - - /** - * - * setLimits. - * - * @param low a double. - * @param up a double. - */ - fun setLimits(low: Double, up: Double) { - require(low != up) { "min == max" } - theLoLimit = low - theUpLimit = up - theLoLimValid = true - theUpLimValid = true - if (low > up) { - theLoLimit = up - theUpLimit = low - } - } - - /** - * - * setLowerLimit. - * - * @param low a double. - */ - fun setLowerLimit(low: Double) { - theLoLimit = low - theUpLimit = 0.0 - theLoLimValid = true - theUpLimValid = false - } - - /** - * - * setUpperLimit. - * - * @param up a double. - */ - fun setUpperLimit(up: Double) { - theLoLimit = 0.0 - theUpLimit = up - theLoLimValid = false - theUpLimValid = true - } - //interaction - /** - * - * setValue. - * - * @param val a double. - */ - fun setValue(`val`: Double) { - theValue = `val` - } - - /** - * - * upperLimit. - * - * @return a double. - */ - fun upperLimit(): Double { - return theUpLimit - } - - /** - * - * value. - * - * @return a double. - */ - fun value(): Double { - return theValue - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt deleted file mode 100644 index 4b75858e1..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * - * @version $Id$ - */ -class MnAlgebraicSymMatrix(n: Int) { - private val theData: DoubleArray - private val theNRow: Int - private val theSize: Int - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnAlgebraicSymMatrix] object. - */ - fun copy(): MnAlgebraicSymMatrix { - val copy = MnAlgebraicSymMatrix(theNRow) - java.lang.System.arraycopy(theData, 0, copy.theData, 0, theSize) - return copy - } - - fun data(): DoubleArray { - return theData - } - - fun eigenvalues(): ArrayRealVector { - val nrow = theNRow - val tmp = DoubleArray((nrow + 1) * (nrow + 1)) - val work = DoubleArray(1 + 2 * nrow) - for (i in 0 until nrow) { - for (j in 0..i) { - tmp[1 + i + (1 + j) * nrow] = get(i, j) - tmp[(1 + i) * nrow + (1 + j)] = get(i, j) - } - } - val info = mneigen(tmp, nrow, nrow, work.size, work, 1e-6) - if (info != 0) { - throw EigenvaluesException() - } - val result = ArrayRealVector(nrow) - for (i in 0 until nrow) { - result.setEntry(i, work[1 + i]) - } - return result - } - - operator fun get(row: Int, col: Int): Double { - if (row >= theNRow || col >= theNRow) { - throw ArrayIndexOutOfBoundsException() - } - return theData[theIndex(row, col)] - } - - @Throws(SingularMatrixException::class) - fun invert() { - if (theSize == 1) { - val tmp = theData[0] - if (tmp <= 0.0) { - throw SingularMatrixException() - } - theData[0] = 1.0 / tmp - } else { - val nrow = theNRow - val s = DoubleArray(nrow) - val q = DoubleArray(nrow) - val pp = DoubleArray(nrow) - for (i in 0 until nrow) { - val si = theData[theIndex(i, i)] - if (si < 0.0) { - throw SingularMatrixException() - } - s[i] = 1.0 / sqrt(si) - } - for (i in 0 until nrow) { - for (j in i until nrow) { - theData[theIndex(i, j)] *= s[i] * s[j] - } - } - for (i in 0 until nrow) { - var k = i - if (theData[theIndex(k, k)] == 0.0) { - throw SingularMatrixException() - } - q[k] = 1.0 / theData[theIndex(k, k)] - pp[k] = 1.0 - theData[theIndex(k, k)] = 0.0 - val kp1 = k + 1 - if (k != 0) { - for (j in 0 until k) { - val index = theIndex(j, k) - pp[j] = theData[index] - q[j] = theData[index] * q[k] - theData[index] = 0.0 - } - } - if (k != nrow - 1) { - for (j in kp1 until nrow) { - val index = theIndex(k, j) - pp[j] = theData[index] - q[j] = -theData[index] * q[k] - theData[index] = 0.0 - } - } - for (j in 0 until nrow) { - k = j - while (k < nrow) { - theData[theIndex(j, k)] += pp[j] * q[k] - k++ - } - } - } - for (j in 0 until nrow) { - for (k in j until nrow) { - theData[theIndex(j, k)] *= s[j] * s[k] - } - } - } - } - - fun ncol(): Int { - return nrow() - } - - fun nrow(): Int { - return theNRow - } - - operator fun set(row: Int, col: Int, value: Double) { - if (row >= theNRow || col >= theNRow) { - throw ArrayIndexOutOfBoundsException() - } - theData[theIndex(row, col)] = value - } - - fun size(): Int { - return theSize - } - - private fun theIndex(row: Int, col: Int): Int { - return if (row > col) { - col + row * (row + 1) / 2 - } else { - row + col * (col + 1) / 2 - } - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } /* mneig_ */ - - private inner class EigenvaluesException : RuntimeException() - companion object { - private fun mneigen(a: DoubleArray, ndima: Int, n: Int, mits: Int, work: DoubleArray, precis: Double): Int { - - /* System generated locals */ - var i__2: Int - var i__3: Int - - /* Local variables */ - var b: Double - var c__: Double - var f: Double - var h__: Double - var i__: Int - var j: Int - var k: Int - var l: Int - var m = 0 - var r__: Double - var s: Double - var i0: Int - var i1: Int - var j1: Int - var m1: Int - var hh: Double - var gl: Double - var pr: Double - var pt: Double - - /* PRECIS is the machine precision EPSMAC */ - /* Parameter adjustments */ - val a_dim1: Int = ndima - val a_offset: Int = 1 + a_dim1 * 1 - - /* Function Body */ - var ifault = 1 - i__ = n - var i__1: Int = n - i1 = 2 - while (i1 <= i__1) { - l = i__ - 2 - f = a[i__ + (i__ - 1) * a_dim1] - gl = 0.0 - if (l >= 1) { - i__2 = l - k = 1 - while (k <= i__2) { - - /* Computing 2nd power */ - val r__1 = a[i__ + k * a_dim1] - gl += r__1 * r__1 - ++k - } - } - /* Computing 2nd power */h__ = gl + f * f - if (gl <= 1e-35) { - work[i__] = 0.0 - work[n + i__] = f - } else { - ++l - gl = sqrt(h__) - if (f >= 0.0) { - gl = -gl - } - work[n + i__] = gl - h__ -= f * gl - a[i__ + (i__ - 1) * a_dim1] = f - gl - f = 0.0 - i__2 = l - j = 1 - while (j <= i__2) { - a[j + i__ * a_dim1] = a[i__ + j * a_dim1] / h__ - gl = 0.0 - i__3 = j - k = 1 - while (k <= i__3) { - gl += a[j + k * a_dim1] * a[i__ + k * a_dim1] - ++k - } - if (j < l) { - j1 = j + 1 - i__3 = l - k = j1 - while (k <= i__3) { - gl += a[k + j * a_dim1] * a[i__ + k * a_dim1] - ++k - } - } - work[n + j] = gl / h__ - f += gl * a[j + i__ * a_dim1] - ++j - } - hh = f / (h__ + h__) - i__2 = l - j = 1 - while (j <= i__2) { - f = a[i__ + j * a_dim1] - gl = work[n + j] - hh * f - work[n + j] = gl - i__3 = j - k = 1 - while (k <= i__3) { - a[j + k * a_dim1] = a[j + k * a_dim1] - f * work[n + k] - (gl - * a[i__ + k * a_dim1]) - ++k - } - ++j - } - work[i__] = h__ - } - --i__ - ++i1 - } - work[1] = 0.0 - work[n + 1] = 0.0 - i__1 = n - i__ = 1 - while (i__ <= i__1) { - l = i__ - 1 - if (work[i__] != 0.0 && l != 0) { - i__3 = l - j = 1 - while (j <= i__3) { - gl = 0.0 - i__2 = l - k = 1 - while (k <= i__2) { - gl += a[i__ + k * a_dim1] * a[k + j * a_dim1] - ++k - } - i__2 = l - k = 1 - while (k <= i__2) { - a[k + j * a_dim1] -= gl * a[k + i__ * a_dim1] - ++k - } - ++j - } - } - work[i__] = a[i__ + i__ * a_dim1] - a[i__ + i__ * a_dim1] = 1.0 - if (l != 0) { - i__2 = l - j = 1 - while (j <= i__2) { - a[i__ + j * a_dim1] = 0.0 - a[j + i__ * a_dim1] = 0.0 - ++j - } - } - ++i__ - } - val n1: Int = n - 1 - i__1 = n - i__ = 2 - while (i__ <= i__1) { - i0 = n + i__ - 1 - work[i0] = work[i0 + 1] - ++i__ - } - work[n + n] = 0.0 - b = 0.0 - f = 0.0 - i__1 = n - l = 1 - while (l <= i__1) { - j = 0 - h__ = precis * (abs(work[l]) + abs(work[n + l])) - if (b < h__) { - b = h__ - } - i__2 = n - m1 = l - while (m1 <= i__2) { - m = m1 - if (abs(work[n + m]) <= b) { - break - } - ++m1 - } - if (m != l) { - while (true) { - if (j == mits) { - return ifault - } - ++j - pt = (work[l + 1] - work[l]) / (work[n + l] * 2.0) - r__ = sqrt(pt * pt + 1.0) - pr = pt + r__ - if (pt < 0.0) { - pr = pt - r__ - } - h__ = work[l] - work[n + l] / pr - i__2 = n - i__ = l - while (i__ <= i__2) { - work[i__] -= h__ - ++i__ - } - f += h__ - pt = work[m] - c__ = 1.0 - s = 0.0 - m1 = m - 1 - i__ = m - i__2 = m1 - i1 = l - while (i1 <= i__2) { - j = i__ - --i__ - gl = c__ * work[n + i__] - h__ = c__ * pt - if (abs(pt) < abs(work[n + i__])) { - c__ = pt / work[n + i__] - r__ = sqrt(c__ * c__ + 1.0) - work[n + j] = s * work[n + i__] * r__ - s = 1.0 / r__ - c__ /= r__ - } else { - c__ = work[n + i__] / pt - r__ = sqrt(c__ * c__ + 1.0) - work[n + j] = s * pt * r__ - s = c__ / r__ - c__ = 1.0 / r__ - } - pt = c__ * work[i__] - s * gl - work[j] = h__ + s * (c__ * gl + s * work[i__]) - i__3 = n - k = 1 - while (k <= i__3) { - h__ = a[k + j * a_dim1] - a[k + j * a_dim1] = s * a[k + i__ * a_dim1] + c__ * h__ - a[k + i__ * a_dim1] = c__ * a[k + i__ * a_dim1] - s * h__ - ++k - } - ++i1 - } - work[n + l] = s * pt - work[l] = c__ * pt - if (abs(work[n + l]) <= b) { - break - } - } - } - work[l] += f - ++l - } - i__1 = n1 - i__ = 1 - while (i__ <= i__1) { - k = i__ - pt = work[i__] - i1 = i__ + 1 - i__3 = n - j = i1 - while (j <= i__3) { - if (work[j] < pt) { - k = j - pt = work[j] - } - ++j - } - if (k != i__) { - work[k] = work[i__] - work[i__] = pt - i__3 = n - j = 1 - while (j <= i__3) { - pt = a[j + i__ * a_dim1] - a[j + i__ * a_dim1] = a[j + k * a_dim1] - a[j + k * a_dim1] = pt - ++j - } - } - ++i__ - } - ifault = 0 - return ifault - } /* mneig_ */ - } - - init { - require(n >= 0) { "Invalid matrix size: $n" } - theSize = n * (n + 1) / 2 - theNRow = n - theData = DoubleArray(theSize) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt deleted file mode 100644 index 025eea4ae..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * Base class for minimizers. - * - * @version $Id$ - * @author Darksnake - */ -abstract class MnApplication { - /* package protected */ - var checkAnalyticalDerivatives: Boolean - - /* package protected */ /* package protected */ - var theErrorDef = 1.0 /* package protected */ - var theFCN: MultiFunction? - - /* package protected */ /* package protected */ - var theNumCall /* package protected */ = 0 - var theState: MnUserParameterState - - /* package protected */ - var theStrategy: MnStrategy - - /* package protected */ - var useAnalyticalDerivatives: Boolean - - /* package protected */ - internal constructor(fcn: MultiFunction?, state: MnUserParameterState, stra: MnStrategy) { - theFCN = fcn - theState = state - theStrategy = stra - checkAnalyticalDerivatives = true - useAnalyticalDerivatives = true - } - - internal constructor(fcn: MultiFunction?, state: MnUserParameterState, stra: MnStrategy, nfcn: Int) { - theFCN = fcn - theState = state - theStrategy = stra - theNumCall = nfcn - checkAnalyticalDerivatives = true - useAnalyticalDerivatives = true - } - - /** - * - * MultiFunction. - * - * @return a [MultiFunction] object. - */ - fun MultiFunction(): MultiFunction? { - return theFCN - } - - /** - * add free parameter - * - * @param err a double. - * @param val a double. - * @param name a [String] object. - */ - fun add(name: String, `val`: Double, err: Double) { - theState.add(name, `val`, err) - } - - /** - * add limited parameter - * - * @param up a double. - * @param low a double. - * @param name a [String] object. - * @param val a double. - * @param err a double. - */ - fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { - theState.add(name, `val`, err, low, up) - } - - /** - * add const parameter - * - * @param name a [String] object. - * @param val a double. - */ - fun add(name: String, `val`: Double) { - theState.add(name, `val`) - } - - /** - * - * checkAnalyticalDerivatives. - * - * @return a boolean. - */ - fun checkAnalyticalDerivatives(): Boolean { - return checkAnalyticalDerivatives - } - - /** - * - * covariance. - * - * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun covariance(): MnUserCovariance { - return theState.covariance() - } - - /** - * - * error. - * - * @param index a int. - * @return a double. - */ - fun error(index: Int): Double { - return theState.error(index) - } - - /** - * - * error. - * - * @param name a [String] object. - * @return a double. - */ - fun error(name: String?): Double { - return theState.error(name) - } - - /** - * - * errorDef. - * - * @return a double. - */ - fun errorDef(): Double { - return theErrorDef - } - - /** - * - * errors. - * - * @return an array of double. - */ - fun errors(): DoubleArray { - return theState.errors() - } - - fun ext2int(i: Int, value: Double): Double { - return theState.ext2int(i, value) - } - - fun extOfInt(i: Int): Int { - return theState.extOfInt(i) - } - //interaction via external number of parameter - /** - * - * fix. - * - * @param index a int. - */ - fun fix(index: Int) { - theState.fix(index) - } - //interaction via name of parameter - /** - * - * fix. - * - * @param name a [String] object. - */ - fun fix(name: String?) { - theState.fix(name) - } - - /** - * convert name into external number of parameter - * - * @param name a [String] object. - * @return a int. - */ - fun index(name: String?): Int { - return theState.index(name) - } - - // transformation internal <-> external - fun int2ext(i: Int, value: Double): Double { - return theState.int2ext(i, value) - } - - fun intOfExt(i: Int): Int { - return theState.intOfExt(i) - } - - /** - * - * minimize. - * - * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun minimize(): FunctionMinimum { - return minimize(DEFAULT_MAXFCN) - } - - /** - * - * minimize. - * - * @param maxfcn a int. - * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun minimize(maxfcn: Int): FunctionMinimum { - return minimize(maxfcn, DEFAULT_TOLER) - } - - /** - * Causes minimization of the FCN and returns the result in form of a - * FunctionMinimum. - * - * @param maxfcn specifies the (approximate) maximum number of function - * calls after which the calculation will be stopped even if it has not yet - * converged. - * @param toler specifies the required tolerance on the function value at - * the minimum. The default tolerance value is 0.1, and the minimization - * will stop when the estimated vertical distance to the minimum (EDM) is - * less than 0:001*tolerance*errorDef - * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun minimize(maxfcn: Int, toler: Double): FunctionMinimum { - var maxfcn = maxfcn - check(theState.isValid()) { "Invalid state" } - val npar = variableParameters() - if (maxfcn == 0) { - maxfcn = 200 + 100 * npar + 5 * npar * npar - } - val min: FunctionMinimum = minimizer().minimize(theFCN, - theState, - theStrategy, - maxfcn, - toler, - theErrorDef, - useAnalyticalDerivatives, - checkAnalyticalDerivatives) - theNumCall += min.nfcn() - theState = min.userState() - return min - } - - abstract fun minimizer(): ModularFunctionMinimizer - - // facade: forward interface of MnUserParameters and MnUserTransformation - fun minuitParameters(): List { - return theState.minuitParameters() - } - - /** - * convert external number into name of parameter - * - * @param index a int. - * @return a [String] object. - */ - fun name(index: Int): String { - return theState.name(index) - } - - /** - * - * numOfCalls. - * - * @return a int. - */ - fun numOfCalls(): Int { - return theNumCall - } - - /** - * access to single parameter - * @param i - * @return - */ - fun parameter(i: Int): MinuitParameter { - return theState.parameter(i) - } - - /** - * - * parameters. - * - * @return a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - fun parameters(): MnUserParameters { - return theState.parameters() - } - - /** - * access to parameters and errors in column-wise representation - * - * @return an array of double. - */ - fun params(): DoubleArray { - return theState.params() - } - - /** - * - * precision. - * - * @return a [hep.dataforge.MINUIT.MnMachinePrecision] object. - */ - fun precision(): MnMachinePrecision { - return theState.precision() - } - - /** - * - * release. - * - * @param index a int. - */ - fun release(index: Int) { - theState.release(index) - } - - /** - * - * release. - * - * @param name a [String] object. - */ - fun release(name: String?) { - theState.release(name) - } - - /** - * - * removeLimits. - * - * @param index a int. - */ - fun removeLimits(index: Int) { - theState.removeLimits(index) - } - - /** - * - * removeLimits. - * - * @param name a [String] object. - */ - fun removeLimits(name: String?) { - theState.removeLimits(name) - } - - /** - * Minuit does a check of the user gradient at the beginning, if this is not - * wanted the set this to "false". - * - * @param check a boolean. - */ - fun setCheckAnalyticalDerivatives(check: Boolean) { - checkAnalyticalDerivatives = check - } - - /** - * - * setError. - * - * @param index a int. - * @param err a double. - */ - fun setError(index: Int, err: Double) { - theState.setError(index, err) - } - - /** - * - * setError. - * - * @param name a [String] object. - * @param err a double. - */ - fun setError(name: String?, err: Double) { - theState.setError(name, err) - } - - /** - * errorDef() is the error definition of the function. E.g. is 1 if function - * is Chi2 and 0.5 if function is -logLikelihood. If the user wants instead - * the 2-sigma errors, errorDef() = 4, as Chi2(x+n*sigma) = Chi2(x) + n*n. - * - * @param errorDef a double. - */ - fun setErrorDef(errorDef: Double) { - theErrorDef = errorDef - } - - /** - * - * setLimits. - * - * @param index a int. - * @param low a double. - * @param up a double. - */ - fun setLimits(index: Int, low: Double, up: Double) { - theState.setLimits(index, low, up) - } - - /** - * - * setLimits. - * - * @param name a [String] object. - * @param low a double. - * @param up a double. - */ - fun setLimits(name: String?, low: Double, up: Double) { - theState.setLimits(name, low, up) - } - - /** - * - * setPrecision. - * - * @param prec a double. - */ - fun setPrecision(prec: Double) { - theState.setPrecision(prec) - } - - /** - * By default if the function to be minimized implements MultiFunction then - * the analytical gradient provided by the function will be used. Set this - * to - * false to disable this behaviour and force numerical - * calculation of the gradient. - * - * @param use a boolean. - */ - fun setUseAnalyticalDerivatives(use: Boolean) { - useAnalyticalDerivatives = use - } - - /** - * - * setValue. - * - * @param index a int. - * @param val a double. - */ - fun setValue(index: Int, `val`: Double) { - theState.setValue(index, `val`) - } - - /** - * - * setValue. - * - * @param name a [String] object. - * @param val a double. - */ - fun setValue(name: String?, `val`: Double) { - theState.setValue(name, `val`) - } - - /** - * - * state. - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun state(): MnUserParameterState { - return theState - } - - /** - * - * strategy. - * - * @return a [hep.dataforge.MINUIT.MnStrategy] object. - */ - fun strategy(): MnStrategy { - return theStrategy - } - - /** - * - * useAnalyticalDerivaties. - * - * @return a boolean. - */ - fun useAnalyticalDerivaties(): Boolean { - return useAnalyticalDerivatives - } - - /** - * - * value. - * - * @param index a int. - * @return a double. - */ - fun value(index: Int): Double { - return theState.value(index) - } - - /** - * - * value. - * - * @param name a [String] object. - * @return a double. - */ - fun value(name: String?): Double { - return theState.value(name) - } - - /** - * - * variableParameters. - * - * @return a int. - */ - fun variableParameters(): Int { - return theState.variableParameters() - } - - companion object { - var DEFAULT_MAXFCN = 0 - var DEFAULT_STRATEGY = 1 - var DEFAULT_TOLER = 0.1 - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt deleted file mode 100644 index 1b700f4e2..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * API class for Contours error analysis (2-dim errors). Minimization has to be - * done before and minimum must be valid. Possibility to ask only for the points - * or the points and associated Minos errors. - * - * @version $Id$ - * @author Darksnake - */ -class MnContours(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) { - private var theFCN: MultiFunction? = null - private var theMinimum: FunctionMinimum? = null - private var theStrategy: MnStrategy? = null - - /** - * construct from FCN + minimum - * - * @param fcn a [MultiFunction] object. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - constructor(fcn: MultiFunction?, min: FunctionMinimum?) : this(fcn, min, MnApplication.DEFAULT_STRATEGY) - - /** - * construct from FCN + minimum + strategy - * - * @param stra a int. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, min: FunctionMinimum?, stra: Int) : this(fcn, min, MnStrategy(stra)) - - /** - * - * contour. - * - * @param px a int. - * @param py a int. - * @return a [hep.dataforge.MINUIT.ContoursError] object. - */ - fun contour(px: Int, py: Int): ContoursError { - return contour(px, py, 1.0) - } - - /** - * - * contour. - * - * @param px a int. - * @param py a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.ContoursError] object. - */ - fun contour(px: Int, py: Int, errDef: Double): ContoursError { - return contour(px, py, errDef, 20) - } - - /** - * Causes a CONTOURS error analysis and returns the result in form of - * ContoursError. As a by-product ContoursError keeps the MinosError - * information of parameters parx and pary. The result ContoursError can be - * easily printed using MnPrint or toString(). - * - * @param npoints a int. - * @param px a int. - * @param py a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.ContoursError] object. - */ - fun contour(px: Int, py: Int, errDef: Double, npoints: Int): ContoursError { - var errDef = errDef - errDef *= theMinimum!!.errorDef() - assert(npoints > 3) - val maxcalls: Int = 100 * (npoints + 5) * (theMinimum!!.userState().variableParameters() + 1) - var nfcn = 0 - val result: MutableList = java.util.ArrayList(npoints) - val states: List = java.util.ArrayList() - val toler = 0.05 - - //get first four points - val minos = MnMinos(theFCN, theMinimum, theStrategy) - val valx: Double = theMinimum!!.userState().value(px) - val valy: Double = theMinimum!!.userState().value(py) - val mex: MinosError = minos.minos(px, errDef) - nfcn += mex.nfcn() - if (!mex.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find first two points.") - return ContoursError(px, py, result, mex, mex, nfcn) - } - val ex: Range = mex.range() - val mey: MinosError = minos.minos(py, errDef) - nfcn += mey.nfcn() - if (!mey.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find second two points.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - val ey: Range = mey.range() - val migrad = MnMigrad(theFCN, - theMinimum!!.userState().copy(), - MnStrategy(max(0, theStrategy!!.strategy() - 1))) - migrad.fix(px) - migrad.setValue(px, valx + ex.getSecond()) - val exy_up: FunctionMinimum = migrad.minimize() - nfcn += exy_up.nfcn() - if (!exy_up.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find upper y value for x parameter $px.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - migrad.setValue(px, valx + ex.getFirst()) - val exy_lo: FunctionMinimum = migrad.minimize() - nfcn += exy_lo.nfcn() - if (!exy_lo.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find lower y value for x parameter $px.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - val migrad1 = MnMigrad(theFCN, - theMinimum!!.userState().copy(), - MnStrategy(max(0, theStrategy!!.strategy() - 1))) - migrad1.fix(py) - migrad1.setValue(py, valy + ey.getSecond()) - val eyx_up: FunctionMinimum = migrad1.minimize() - nfcn += eyx_up.nfcn() - if (!eyx_up.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find upper x value for y parameter $py.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - migrad1.setValue(py, valy + ey.getFirst()) - val eyx_lo: FunctionMinimum = migrad1.minimize() - nfcn += eyx_lo.nfcn() - if (!eyx_lo.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find lower x value for y parameter $py.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - val scalx: Double = 1.0 / (ex.getSecond() - ex.getFirst()) - val scaly: Double = 1.0 / (ey.getSecond() - ey.getFirst()) - result.add(Range(valx + ex.getFirst(), exy_lo.userState().value(py))) - result.add(Range(eyx_lo.userState().value(px), valy + ey.getFirst())) - result.add(Range(valx + ex.getSecond(), exy_up.userState().value(py))) - result.add(Range(eyx_up.userState().value(px), valy + ey.getSecond())) - val upar: MnUserParameterState = theMinimum!!.userState().copy() - upar.fix(px) - upar.fix(py) - val par = intArrayOf(px, py) - val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef) - for (i in 4 until npoints) { - var idist1: Range = result[result.size - 1] - var idist2: Range = result[0] - var pos2 = 0 - val distx: Double = idist1.getFirst() - idist2.getFirst() - val disty: Double = idist1.getSecond() - idist2.getSecond() - var bigdis = scalx * scalx * distx * distx + scaly * scaly * disty * disty - for (j in 0 until result.size - 1) { - val ipair: Range = result[j] - val distx2: Double = ipair.getFirst() - result[j + 1].getFirst() - val disty2: Double = ipair.getSecond() - result[j + 1].getSecond() - val dist = scalx * scalx * distx2 * distx2 + scaly * scaly * disty2 * disty2 - if (dist > bigdis) { - bigdis = dist - idist1 = ipair - idist2 = result[j + 1] - pos2 = j + 1 - } - } - val a1 = 0.5 - val a2 = 0.5 - var sca = 1.0 - while (true) { - if (nfcn > maxcalls) { - MINUITPlugin.logStatic("MnContours: maximum number of function calls exhausted.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - val xmidcr: Double = a1 * idist1.getFirst() + a2 * idist2.getFirst() - val ymidcr: Double = a1 * idist1.getSecond() + a2 * idist2.getSecond() - val xdir: Double = idist2.getSecond() - idist1.getSecond() - val ydir: Double = idist1.getFirst() - idist2.getFirst() - val scalfac: Double = - sca * max(abs(xdir * scalx), abs(ydir * scaly)) - val xdircr = xdir / scalfac - val ydircr = ydir / scalfac - val pmid = doubleArrayOf(xmidcr, ymidcr) - val pdir = doubleArrayOf(xdircr, ydircr) - val opt: MnCross = cross.cross(par, pmid, pdir, toler, maxcalls) - nfcn += opt.nfcn() - if (opt.isValid()) { - val aopt: Double = opt.value() - if (pos2 == 0) { - result.add(Range(xmidcr + aopt * xdircr, ymidcr + aopt * ydircr)) - } else { - result.add(pos2, Range(xmidcr + aopt * xdircr, ymidcr + aopt * ydircr)) - } - break - } - if (sca < 0.0) { - MINUITPlugin.logStatic("MnContours is unable to find point " + (i + 1) + " on contour.") - MINUITPlugin.logStatic("MnContours finds only $i points.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - sca = -1.0 - } - } - return ContoursError(px, py, result, mex, mey, nfcn) - } - - /** - * - * points. - * - * @param px a int. - * @param py a int. - * @return a [List] object. - */ - fun points(px: Int, py: Int): List { - return points(px, py, 1.0) - } - - /** - * - * points. - * - * @param px a int. - * @param py a int. - * @param errDef a double. - * @return a [List] object. - */ - fun points(px: Int, py: Int, errDef: Double): List { - return points(px, py, errDef, 20) - } - - /** - * Calculates one function contour of FCN with respect to parameters parx - * and pary. The return value is a list of (x,y) points. FCN minimized - * always with respect to all other n - 2 variable parameters (if any). - * MINUITPlugin will try to find n points on the contour (default 20). To - * calculate more than one contour, the user needs to set the error - * definition in its FCN to the appropriate value for the desired confidence - * level and call this method for each contour. - * - * @param npoints a int. - * @param px a int. - * @param py a int. - * @param errDef a double. - * @return a [List] object. - */ - fun points(px: Int, py: Int, errDef: Double, npoints: Int): List { - val cont: ContoursError = contour(px, py, errDef, npoints) - return cont.points() - } - - fun strategy(): MnStrategy? { - return theStrategy - } - - /** - * construct from FCN + minimum + strategy - * - * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - * @param fcn a [MultiFunction] object. - */ - init { - theFCN = fcn - theMinimum = min - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt deleted file mode 100644 index 7614a93b0..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin - -/** - * - * @version $Id$ - */ -internal object MnCovarianceSqueeze { - fun squeeze(cov: MnUserCovariance, n: Int): MnUserCovariance { - assert(cov.nrow() > 0) - assert(n < cov.nrow()) - val hess = MnAlgebraicSymMatrix(cov.nrow()) - for (i in 0 until cov.nrow()) { - for (j in i until cov.nrow()) { - hess[i, j] = cov[i, j] - } - } - try { - hess.invert() - } catch (x: SingularMatrixException) { - MINUITPlugin.logStatic("MnUserCovariance inversion failed; return diagonal matrix;") - val result = MnUserCovariance(cov.nrow() - 1) - var i = 0 - var j = 0 - while (i < cov.nrow()) { - if (i == n) { - i++ - continue - } - result[j, j] = cov[i, i] - j++ - i++ - } - return result - } - val squeezed: MnAlgebraicSymMatrix = squeeze(hess, n) - try { - squeezed.invert() - } catch (x: SingularMatrixException) { - MINUITPlugin.logStatic("MnUserCovariance back-inversion failed; return diagonal matrix;") - val result = MnUserCovariance(squeezed.nrow()) - var i = 0 - while (i < squeezed.nrow()) { - result[i, i] = 1.0 / squeezed[i, i] - i++ - } - return result - } - return MnUserCovariance(squeezed.data(), squeezed.nrow()) - } - - fun squeeze(err: MinimumError, n: Int): MinimumError { - val hess: MnAlgebraicSymMatrix = err.hessian() - val squeezed: MnAlgebraicSymMatrix = squeeze(hess, n) - try { - squeezed.invert() - } catch (x: SingularMatrixException) { - MINUITPlugin.logStatic("MnCovarianceSqueeze: MinimumError inversion fails; return diagonal matrix.") - val tmp = MnAlgebraicSymMatrix(squeezed.nrow()) - var i = 0 - while (i < squeezed.nrow()) { - tmp[i, i] = 1.0 / squeezed[i, i] - i++ - } - return MinimumError(tmp, MnInvertFailed()) - } - return MinimumError(squeezed, err.dcovar()) - } - - fun squeeze(hess: MnAlgebraicSymMatrix, n: Int): MnAlgebraicSymMatrix { - assert(hess.nrow() > 0) - assert(n < hess.nrow()) - val hs = MnAlgebraicSymMatrix(hess.nrow() - 1) - var i = 0 - var j = 0 - while (i < hess.nrow()) { - if (i == n) { - i++ - continue - } - var k = i - var l = j - while (k < hess.nrow()) { - if (k == n) { - k++ - continue - } - hs[j, l] = hess[i, k] - l++ - k++ - } - j++ - i++ - } - return hs - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnCross.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnCross.kt deleted file mode 100644 index f1487b106..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnCross.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * MnCross class. - * - * @version $Id$ - * @author Darksnake - */ -class MnCross { - private var theLimset = false - private var theMaxFcn = false - private var theNFcn = 0 - private var theNewMin = false - private var theState: MnUserParameterState - private var theValid = false - private var theValue = 0.0 - - internal constructor() { - theState = MnUserParameterState() - } - - internal constructor(nfcn: Int) { - theState = MnUserParameterState() - theNFcn = nfcn - } - - internal constructor(value: Double, state: MnUserParameterState, nfcn: Int) { - theValue = value - theState = state - theNFcn = nfcn - theValid = true - } - - internal constructor(state: MnUserParameterState, nfcn: Int, x: CrossParLimit?) { - theState = state - theNFcn = nfcn - theLimset = true - } - - internal constructor(state: MnUserParameterState, nfcn: Int, x: CrossFcnLimit?) { - theState = state - theNFcn = nfcn - theMaxFcn = true - } - - internal constructor(state: MnUserParameterState, nfcn: Int, x: CrossNewMin?) { - theState = state - theNFcn = nfcn - theNewMin = true - } - - fun atLimit(): Boolean { - return theLimset - } - - fun atMaxFcn(): Boolean { - return theMaxFcn - } - - fun isValid(): Boolean { - return theValid - } - - fun newMinimum(): Boolean { - return theNewMin - } - - fun nfcn(): Int { - return theNFcn - } - - fun state(): MnUserParameterState { - return theState - } - - fun value(): Double { - return theValue - } - - internal class CrossFcnLimit - internal class CrossNewMin - internal class CrossParLimit -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnEigen.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnEigen.kt deleted file mode 100644 index d7aade0c9..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnEigen.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector - -/** - * Calculates and the eigenvalues of the user covariance matrix - * MnUserCovariance. - * - * @version $Id$ - * @author Darksnake - */ -object MnEigen { - /* Calculate eigenvalues of the covariance matrix. - * Will perform the calculation of the eigenvalues of the covariance matrix - * and return the result in the form of a double array. - * The eigenvalues are ordered from the smallest to the largest eigenvalue. - */ - /** - * - * eigenvalues. - * - * @param covar a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return an array of double. - */ - fun eigenvalues(covar: MnUserCovariance): DoubleArray { - val cov = MnAlgebraicSymMatrix(covar.nrow()) - for (i in 0 until covar.nrow()) { - for (j in i until covar.nrow()) { - cov[i, j] = covar[i, j] - } - } - val eigen: RealVector = cov.eigenvalues() - return eigen.toArray() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnFcn.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnFcn.kt deleted file mode 100644 index b11f71035..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnFcn.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * Функция, которая помнит количество вызовов себя и ErrorDef - * @version $Id$ - */ -class MnFcn(fcn: MultiFunction?, errorDef: Double) { - private val theErrorDef: Double - private val theFCN: MultiFunction? - protected var theNumCall: Int - fun errorDef(): Double { - return theErrorDef - } - - fun fcn(): MultiFunction? { - return theFCN - } - - fun numOfCalls(): Int { - return theNumCall - } - - fun value(v: RealVector): Double { - theNumCall++ - return theFCN.value(v.toArray()) - } - - init { - theFCN = fcn - theNumCall = 0 - theErrorDef = errorDef - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt deleted file mode 100644 index a05590e53..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* -import kotlin.math.* - -/** - * - * @version $Id$ - */ -internal class MnFunctionCross( - fcn: MultiFunction?, - state: MnUserParameterState, - fval: Double, - stra: MnStrategy?, - errorDef: Double -) { - private val theErrorDef: Double - private val theFCN: MultiFunction? - private val theFval: Double - private val theState: MnUserParameterState - private val theStrategy: MnStrategy? - fun cross(par: IntArray, pmid: DoubleArray, pdir: DoubleArray, tlr: Double, maxcalls: Int): MnCross { - val npar = par.size - var nfcn = 0 - val prec: MnMachinePrecision = theState.precision() - val tlf = tlr * theErrorDef - var tla = tlr - val maxitr = 15 - var ipt = 0 - val aminsv = theFval - val aim = aminsv + theErrorDef - var aopt = 0.0 - var limset = false - val alsb = DoubleArray(3) - val flsb = DoubleArray(3) - val up = theErrorDef - var aulim = 100.0 - for (i in par.indices) { - val kex = par[i] - if (theState.parameter(kex).hasLimits()) { - val zmid = pmid[i] - val zdir = pdir[i] - if (abs(zdir) < theState.precision().eps()) { - continue - } - if (zdir > 0.0 && theState.parameter(kex).hasUpperLimit()) { - val zlim: Double = theState.parameter(kex).upperLimit() - aulim = min(aulim, (zlim - zmid) / zdir) - } else if (zdir < 0.0 && theState.parameter(kex).hasLowerLimit()) { - val zlim: Double = theState.parameter(kex).lowerLimit() - aulim = min(aulim, (zlim - zmid) / zdir) - } - } - } - if (aulim < aopt + tla) { - limset = true - } - val migrad = MnMigrad(theFCN, theState, MnStrategy(max(0, theStrategy!!.strategy() - 1))) - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i]) - } - val min0: FunctionMinimum = migrad.minimize(maxcalls, tlr) - nfcn += min0.nfcn() - if (min0.hasReachedCallLimit()) { - return MnCross(min0.userState(), nfcn, MnCross.CrossFcnLimit()) - } - if (!min0.isValid()) { - return MnCross(nfcn) - } - if (limset && min0.fval() < aim) { - return MnCross(min0.userState(), nfcn, MnCross.CrossParLimit()) - } - ipt++ - alsb[0] = 0.0 - flsb[0] = min0.fval() - flsb[0] = max(flsb[0], aminsv + 0.1 * up) - aopt = sqrt(up / (flsb[0] - aminsv)) - 1.0 - if (abs(flsb[0] - aim) < tlf) { - return MnCross(aopt, min0.userState(), nfcn) - } - if (aopt > 1.0) { - aopt = 1.0 - } - if (aopt < -0.5) { - aopt = -0.5 - } - limset = false - if (aopt > aulim) { - aopt = aulim - limset = true - } - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) - } - var min1: FunctionMinimum = migrad.minimize(maxcalls, tlr) - nfcn += min1.nfcn() - if (min1.hasReachedCallLimit()) { - return MnCross(min1.userState(), nfcn, MnCross.CrossFcnLimit()) - } - if (!min1.isValid()) { - return MnCross(nfcn) - } - if (limset && min1.fval() < aim) { - return MnCross(min1.userState(), nfcn, MnCross.CrossParLimit()) - } - ipt++ - alsb[1] = aopt - flsb[1] = min1.fval() - var dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]) - var ecarmn = 0.0 - var ecarmx = 0.0 - var ibest = 0 - var iworst = 0 - var noless = 0 - var min2: FunctionMinimum? = null - L300@ while (true) { - if (dfda < 0.0) { - val maxlk = maxitr - ipt - for (it in 0 until maxlk) { - alsb[0] = alsb[1] - flsb[0] = flsb[1] - aopt = alsb[0] + 0.2 * it - limset = false - if (aopt > aulim) { - aopt = aulim - limset = true - } - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) - } - min1 = migrad.minimize(maxcalls, tlr) - nfcn += min1.nfcn() - if (min1.hasReachedCallLimit()) { - return MnCross(min1.userState(), nfcn, MnCross.CrossFcnLimit()) - } - if (!min1.isValid()) { - return MnCross(nfcn) - } - if (limset && min1.fval() < aim) { - return MnCross(min1.userState(), nfcn, MnCross.CrossParLimit()) - } - ipt++ - alsb[1] = aopt - flsb[1] = min1.fval() - dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]) - if (dfda > 0.0) { - break - } - } - if (ipt > maxitr) { - return MnCross(nfcn) - } - } - L460@ while (true) { - aopt = alsb[1] + (aim - flsb[1]) / dfda - val fdist: Double = - min(abs(aim - flsb[0]), abs(aim - flsb[1])) - val adist: Double = - min(abs(aopt - alsb[0]), abs(aopt - alsb[1])) - tla = tlr - if (abs(aopt) > 1.0) { - tla = tlr * abs(aopt) - } - if (adist < tla && fdist < tlf) { - return MnCross(aopt, min1.userState(), nfcn) - } - if (ipt > maxitr) { - return MnCross(nfcn) - } - val bmin: Double = min(alsb[0], alsb[1]) - 1.0 - if (aopt < bmin) { - aopt = bmin - } - val bmax: Double = max(alsb[0], alsb[1]) + 1.0 - if (aopt > bmax) { - aopt = bmax - } - limset = false - if (aopt > aulim) { - aopt = aulim - limset = true - } - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) - } - min2 = migrad.minimize(maxcalls, tlr) - nfcn += min2.nfcn() - if (min2.hasReachedCallLimit()) { - return MnCross(min2.userState(), nfcn, CrossFcnLimit()) - } - if (!min2.isValid()) { - return MnCross(nfcn) - } - if (limset && min2.fval() < aim) { - return MnCross(min2.userState(), nfcn, MnCross.CrossParLimit()) - } - ipt++ - alsb[2] = aopt - flsb[2] = min2.fval() - ecarmn = abs(flsb[2] - aim) - ecarmx = 0.0 - ibest = 2 - iworst = 0 - noless = 0 - for (i in 0..2) { - val ecart: Double = abs(flsb[i] - aim) - if (ecart > ecarmx) { - ecarmx = ecart - iworst = i - } - if (ecart < ecarmn) { - ecarmn = ecart - ibest = i - } - if (flsb[i] < aim) { - noless++ - } - } - if (noless == 1 || noless == 2) { - break@L300 - } - if (noless == 0 && ibest != 2) { - return MnCross(nfcn) - } - if (noless == 3 && ibest != 2) { - alsb[1] = alsb[2] - flsb[1] = flsb[2] - continue@L300 - } - flsb[iworst] = flsb[2] - alsb[iworst] = alsb[2] - dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]) - } - } - do { - val parbol: MnParabola = MnParabolaFactory.create(MnParabolaPoint(alsb[0], flsb[0]), - MnParabolaPoint(alsb[1], flsb[1]), - MnParabolaPoint( - alsb[2], flsb[2])) - val coeff1: Double = parbol.c() - val coeff2: Double = parbol.b() - val coeff3: Double = parbol.a() - val determ = coeff2 * coeff2 - 4.0 * coeff3 * (coeff1 - aim) - if (determ < prec.eps()) { - return MnCross(nfcn) - } - val rt: Double = sqrt(determ) - val x1 = (-coeff2 + rt) / (2.0 * coeff3) - val x2 = (-coeff2 - rt) / (2.0 * coeff3) - val s1 = coeff2 + 2.0 * x1 * coeff3 - val s2 = coeff2 + 2.0 * x2 * coeff3 - if (s1 * s2 > 0.0) { - MINUITPlugin.logStatic("MnFunctionCross problem 1") - } - aopt = x1 - var slope = s1 - if (s2 > 0.0) { - aopt = x2 - slope = s2 - } - tla = tlr - if (abs(aopt) > 1.0) { - tla = tlr * abs(aopt) - } - if (abs(aopt - alsb[ibest]) < tla && abs(flsb[ibest] - aim) < tlf) { - return MnCross(aopt, min2!!.userState(), nfcn) - } - var ileft = 3 - var iright = 3 - var iout = 3 - ibest = 0 - ecarmx = 0.0 - ecarmn = abs(aim - flsb[0]) - for (i in 0..2) { - val ecart: Double = abs(flsb[i] - aim) - if (ecart < ecarmn) { - ecarmn = ecart - ibest = i - } - if (ecart > ecarmx) { - ecarmx = ecart - } - if (flsb[i] > aim) { - if (iright == 3) { - iright = i - } else if (flsb[i] > flsb[iright]) { - iout = i - } else { - iout = iright - iright = i - } - } else if (ileft == 3) { - ileft = i - } else if (flsb[i] < flsb[ileft]) { - iout = i - } else { - iout = ileft - ileft = i - } - } - if (ecarmx > 10.0 * abs(flsb[iout] - aim)) { - aopt = 0.5 * (aopt + 0.5 * (alsb[iright] + alsb[ileft])) - } - var smalla = 0.1 * tla - if (slope * smalla > tlf) { - smalla = tlf / slope - } - val aleft = alsb[ileft] + smalla - val aright = alsb[iright] - smalla - if (aopt < aleft) { - aopt = aleft - } - if (aopt > aright) { - aopt = aright - } - if (aleft > aright) { - aopt = 0.5 * (aleft + aright) - } - limset = false - if (aopt > aulim) { - aopt = aulim - limset = true - } - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) - } - min2 = migrad.minimize(maxcalls, tlr) - nfcn += min2.nfcn() - if (min2.hasReachedCallLimit()) { - return MnCross(min2.userState(), nfcn, CrossFcnLimit()) - } - if (!min2.isValid()) { - return MnCross(nfcn) - } - if (limset && min2.fval() < aim) { - return MnCross(min2.userState(), nfcn, CrossParLimit()) - } - ipt++ - alsb[iout] = aopt - flsb[iout] = min2.fval() - ibest = iout - } while (ipt < maxitr) - return MnCross(nfcn) - } - - init { - theFCN = fcn - theState = state - theFval = fval - theStrategy = stra - theErrorDef = errorDef - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt deleted file mode 100644 index 939dd7fa0..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.SingularMatrixException - -/** - * - * MnGlobalCorrelationCoeff class. - * - * @version $Id$ - * @author Darksnake - */ -class MnGlobalCorrelationCoeff { - private var theGlobalCC: DoubleArray - private var theValid = false - - internal constructor() { - theGlobalCC = DoubleArray(0) - } - - internal constructor(cov: MnAlgebraicSymMatrix) { - try { - val inv: MnAlgebraicSymMatrix = cov.copy() - inv.invert() - theGlobalCC = DoubleArray(cov.nrow()) - for (i in 0 until cov.nrow()) { - val denom: Double = inv[i, i] * cov[i, i] - if (denom < 1.0 && denom > 0.0) { - theGlobalCC[i] = 0 - } else { - theGlobalCC[i] = sqrt(1.0 - 1.0 / denom) - } - } - theValid = true - } catch (x: SingularMatrixException) { - theValid = false - theGlobalCC = DoubleArray(0) - } - } - - /** - * - * globalCC. - * - * @return an array of double. - */ - fun globalCC(): DoubleArray { - return theGlobalCC - } - - /** - * - * isValid. - * - * @return a boolean. - */ - fun isValid(): Boolean { - return theValid - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt deleted file mode 100644 index 3bb6c4551..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * With MnHesse the user can instructs MINUITPlugin to calculate, by finite - * differences, the Hessian or error matrix. That is, it calculates the full - * matrix of second derivatives of the function with respect to the currently - * variable parameters, and inverts it. - * - * @version $Id$ - * @author Darksnake - */ -class MnHesse { - private var theStrategy: MnStrategy - - /** - * default constructor with default strategy - */ - constructor() { - theStrategy = MnStrategy(1) - } - - /** - * constructor with user-defined strategy level - * - * @param stra a int. - */ - constructor(stra: Int) { - theStrategy = MnStrategy(stra) - } - - /** - * conctructor with specific strategy - * - * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. - */ - constructor(stra: MnStrategy) { - theStrategy = stra - } - /// - /// low-level API - /// - /** - * - * calculate. - * - * @param fcn a [MultiFunction] object. - * @param par an array of double. - * @param err an array of double. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray): MnUserParameterState { - return calculate(fcn, par, err, 0) - } - - /** - * FCN + parameters + errors - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - * @param err an array of double. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, maxcalls: Int): MnUserParameterState { - return calculate(fcn, MnUserParameterState(par, err), maxcalls) - } - - /** - * - * calculate. - * - * @param fcn a [MultiFunction] object. - * @param par an array of double. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance): MnUserParameterState { - return calculate(fcn, par, cov, 0) - } - - /** - * FCN + parameters + MnUserCovariance - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, maxcalls: Int): MnUserParameterState { - return calculate(fcn, MnUserParameterState(par, cov), maxcalls) - } - /// - /// high-level API - /// - /** - * - * calculate. - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: MnUserParameters): MnUserParameterState { - return calculate(fcn, par, 0) - } - - /** - * FCN + MnUserParameters - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: MnUserParameters, maxcalls: Int): MnUserParameterState { - return calculate(fcn, MnUserParameterState(par), maxcalls) - } - - /** - * - * calculate. - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance?): MnUserParameterState { - return calculate(fcn, par, 0) - } - - /** - * FCN + MnUserParameters + MnUserCovariance - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate( - fcn: MultiFunction?, - par: MnUserParameters, - cov: MnUserCovariance, - maxcalls: Int - ): MnUserParameterState { - return calculate(fcn, MnUserParameterState(par, cov), maxcalls) - } - - /** - * FCN + MnUserParameterState - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param state a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, state: MnUserParameterState, maxcalls: Int): MnUserParameterState { - val errDef = 1.0 // FixMe! - val n: Int = state.variableParameters() - val mfcn = MnUserFcn(fcn, errDef, state.getTransformation()) - val x: RealVector = ArrayRealVector(n) - for (i in 0 until n) { - x.setEntry(i, state.intParameters()[i]) - } - val amin: Double = mfcn.value(x) - val gc = Numerical2PGradientCalculator(mfcn, state.getTransformation(), theStrategy) - val par = MinimumParameters(x, amin) - val gra: FunctionGradient = gc.gradient(par) - val tmp: MinimumState = calculate(mfcn, - MinimumState(par, MinimumError(MnAlgebraicSymMatrix(n), 1.0), gra, state.edm(), state.nfcn()), - state.getTransformation(), - maxcalls) - return MnUserParameterState(tmp, errDef, state.getTransformation()) - } - - /// - /// internal interface - /// - fun calculate(mfcn: MnFcn, st: MinimumState, trafo: MnUserTransformation, maxcalls: Int): MinimumState { - var maxcalls = maxcalls - val prec: MnMachinePrecision = trafo.precision() - // make sure starting at the right place - val amin: Double = mfcn.value(st.vec()) - val aimsag: Double = sqrt(prec.eps2()) * (abs(amin) + mfcn.errorDef()) - - // diagonal elements first - val n: Int = st.parameters().vec().getDimension() - if (maxcalls == 0) { - maxcalls = 200 + 100 * n + 5 * n * n - } - var vhmat = MnAlgebraicSymMatrix(n) - var g2: RealVector = st.gradient().getGradientDerivative().copy() - var gst: RealVector = st.gradient().getStep().copy() - var grd: RealVector = st.gradient().getGradient().copy() - var dirin: RealVector = st.gradient().getStep().copy() - val yy: RealVector = ArrayRealVector(n) - if (st.gradient().isAnalytical()) { - val igc = InitialGradientCalculator(mfcn, trafo, theStrategy) - val tmp: FunctionGradient = igc.gradient(st.parameters()) - gst = tmp.getStep().copy() - dirin = tmp.getStep().copy() - g2 = tmp.getGradientDerivative().copy() - } - return try { - val x: RealVector = st.parameters().vec().copy() - for (i in 0 until n) { - val xtf: Double = x.getEntry(i) - val dmin: Double = 8.0 * prec.eps2() * (abs(xtf) + prec.eps2()) - var d: Double = abs(gst.getEntry(i)) - if (d < dmin) { - d = dmin - } - for (icyc in 0 until ncycles()) { - var sag = 0.0 - var fs1 = 0.0 - var fs2 = 0.0 - var multpy = 0 - while (multpy < 5) { - x.setEntry(i, xtf + d) - fs1 = mfcn.value(x) - x.setEntry(i, xtf - d) - fs2 = mfcn.value(x) - x.setEntry(i, xtf) - sag = 0.5 * (fs1 + fs2 - 2.0 * amin) - if (sag > prec.eps2()) { - break - } - if (trafo.parameter(i).hasLimits()) { - if (d > 0.5) { - throw MnHesseFailedException("MnHesse: 2nd derivative zero for parameter") - } - d *= 10.0 - if (d > 0.5) { - d = 0.51 - } - multpy++ - continue - } - d *= 10.0 - multpy++ - } - if (multpy >= 5) { - throw MnHesseFailedException("MnHesse: 2nd derivative zero for parameter") - } - val g2bfor: Double = g2.getEntry(i) - g2.setEntry(i, 2.0 * sag / (d * d)) - grd.setEntry(i, (fs1 - fs2) / (2.0 * d)) - gst.setEntry(i, d) - dirin.setEntry(i, d) - yy.setEntry(i, fs1) - val dlast = d - d = sqrt(2.0 * aimsag / abs(g2.getEntry(i))) - if (trafo.parameter(i).hasLimits()) { - d = min(0.5, d) - } - if (d < dmin) { - d = dmin - } - - // see if converged - if (abs((d - dlast) / d) < tolerstp()) { - break - } - if (abs((g2.getEntry(i) - g2bfor) / g2.getEntry(i)) < tolerg2()) { - break - } - d = min(d, 10.0 * dlast) - d = max(d, 0.1 * dlast) - } - vhmat[i, i] = g2.getEntry(i) - if (mfcn.numOfCalls() - st.nfcn() > maxcalls) { - throw MnHesseFailedException("MnHesse: maximum number of allowed function calls exhausted.") - } - } - if (theStrategy.strategy() > 0) { - // refine first derivative - val hgc = HessianGradientCalculator(mfcn, trafo, theStrategy) - val gr: FunctionGradient = hgc.gradient(st.parameters(), FunctionGradient(grd, g2, gst)) - grd = gr.getGradient() - } - - //off-diagonal elements - for (i in 0 until n) { - x.setEntry(i, x.getEntry(i) + dirin.getEntry(i)) - for (j in i + 1 until n) { - x.setEntry(j, x.getEntry(j) + dirin.getEntry(j)) - val fs1: Double = mfcn.value(x) - val elem: Double = - (fs1 + amin - yy.getEntry(i) - yy.getEntry(j)) / (dirin.getEntry(i) * dirin.getEntry(j)) - vhmat[i, j] = elem - x.setEntry(j, x.getEntry(j) - dirin.getEntry(j)) - } - x.setEntry(i, x.getEntry(i) - dirin.getEntry(i)) - } - - //verify if matrix pos-def (still 2nd derivative) - val tmp: MinimumError = MnPosDef.test(MinimumError(vhmat, 1.0), prec) - vhmat = tmp.invHessian() - try { - vhmat.invert() - } catch (xx: SingularMatrixException) { - throw MnHesseFailedException("MnHesse: matrix inversion fails!") - } - val gr = FunctionGradient(grd, g2, gst) - if (tmp.isMadePosDef()) { - MINUITPlugin.logStatic("MnHesse: matrix is invalid!") - MINUITPlugin.logStatic("MnHesse: matrix is not pos. def.!") - MINUITPlugin.logStatic("MnHesse: matrix was forced pos. def.") - return MinimumState(st.parameters(), - MinimumError(vhmat, MnMadePosDef()), - gr, - st.edm(), - mfcn.numOfCalls()) - } - - //calculate edm - val err = MinimumError(vhmat, 0.0) - val edm: Double = VariableMetricEDMEstimator().estimate(gr, err) - MinimumState(st.parameters(), err, gr, edm, mfcn.numOfCalls()) - } catch (x: MnHesseFailedException) { - MINUITPlugin.logStatic(x.message) - MINUITPlugin.logStatic("MnHesse fails and will return diagonal matrix ") - var j = 0 - while (j < n) { - val tmp = if (g2.getEntry(j) < prec.eps2()) 1.0 else 1.0 / g2.getEntry(j) - vhmat[j, j] = if (tmp < prec.eps2()) 1.0 else tmp - j++ - } - MinimumState(st.parameters(), - MinimumError(vhmat, MnHesseFailed()), - st.gradient(), - st.edm(), - st.nfcn() + mfcn.numOfCalls()) - } - } - - /// forward interface of MnStrategy - fun ncycles(): Int { - return theStrategy.hessianNCycles() - } - - fun tolerg2(): Double { - return theStrategy.hessianG2Tolerance() - } - - fun tolerstp(): Double { - return theStrategy.hessianStepTolerance() - } - - private inner class MnHesseFailedException(message: String?) : java.lang.Exception(message) -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt deleted file mode 100644 index 7b1171d3c..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -internal object MnLineSearch { - fun search( - fcn: MnFcn, - st: MinimumParameters, - step: RealVector, - gdel: Double, - prec: MnMachinePrecision - ): MnParabolaPoint { - var overal = 1000.0 - var undral = -100.0 - val toler = 0.05 - var slamin = 0.0 - val slambg = 5.0 - val alpha = 2.0 - val maxiter = 12 - var niter = 0 - for (i in 0 until step.getDimension()) { - if (abs(step.getEntry(i)) < prec.eps()) { - continue - } - val ratio: Double = abs(st.vec().getEntry(i) / step.getEntry(i)) - if (abs(slamin) < prec.eps()) { - slamin = ratio - } - if (ratio < slamin) { - slamin = ratio - } - } - if (abs(slamin) < prec.eps()) { - slamin = prec.eps() - } - slamin *= prec.eps2() - val F0: Double = st.fval() - val F1: Double = fcn.value(MnUtils.add(st.vec(), step)) - var fvmin: Double = st.fval() - var xvmin = 0.0 - if (F1 < F0) { - fvmin = F1 - xvmin = 1.0 - } - var toler8 = toler - var slamax = slambg - var flast = F1 - var slam = 1.0 - var iterate = false - var p0 = MnParabolaPoint(0.0, F0) - var p1 = MnParabolaPoint(slam, flast) - var F2 = 0.0 - do { - // cut toler8 as function goes up - iterate = false - val pb: MnParabola = MnParabolaFactory.create(p0, gdel, p1) - var denom = 2.0 * (flast - F0 - gdel * slam) / (slam * slam) - if (abs(denom) < prec.eps()) { - denom = -0.1 * gdel - slam = 1.0 - } - if (abs(denom) > prec.eps()) { - slam = -gdel / denom - } - if (slam < 0.0) { - slam = slamax - } - if (slam > slamax) { - slam = slamax - } - if (slam < toler8) { - slam = toler8 - } - if (slam < slamin) { - return MnParabolaPoint(xvmin, fvmin) - } - if (abs(slam - 1.0) < toler8 && p1.y() < p0.y()) { - return MnParabolaPoint(xvmin, fvmin) - } - if (abs(slam - 1.0) < toler8) { - slam = 1.0 + toler8 - } - F2 = fcn.value(MnUtils.add(st.vec(), MnUtils.mul(step, slam))) - if (F2 < fvmin) { - fvmin = F2 - xvmin = slam - } - if (p0.y() - prec.eps() < fvmin && fvmin < p0.y() + prec.eps()) { - iterate = true - flast = F2 - toler8 = toler * slam - overal = slam - toler8 - slamax = overal - p1 = MnParabolaPoint(slam, flast) - niter++ - } - } while (iterate && niter < maxiter) - if (niter >= maxiter) { - // exhausted max number of iterations - return MnParabolaPoint(xvmin, fvmin) - } - var p2 = MnParabolaPoint(slam, F2) - do { - slamax = max(slamax, alpha * abs(xvmin)) - val pb: MnParabola = MnParabolaFactory.create(p0, p1, p2) - if (pb.a() < prec.eps2()) { - val slopem: Double = 2.0 * pb.a() * xvmin + pb.b() - slam = if (slopem < 0.0) { - xvmin + slamax - } else { - xvmin - slamax - } - } else { - slam = pb.min() - if (slam > xvmin + slamax) { - slam = xvmin + slamax - } - if (slam < xvmin - slamax) { - slam = xvmin - slamax - } - } - if (slam > 0.0) { - if (slam > overal) { - slam = overal - } - } else { - if (slam < undral) { - slam = undral - } - } - var F3 = 0.0 - do { - iterate = false - val toler9: Double = max(toler8, abs(toler8 * slam)) - // min. of parabola at one point - if (abs(p0.x() - slam) < toler9 || abs(p1.x() - slam) < toler9 || abs( - p2.x() - slam) < toler9 - ) { - return MnParabolaPoint(xvmin, fvmin) - } - F3 = fcn.value(MnUtils.add(st.vec(), MnUtils.mul(step, slam))) - // if latest point worse than all three previous, cut step - if (F3 > p0.y() && F3 > p1.y() && F3 > p2.y()) { - if (slam > xvmin) { - overal = min(overal, slam - toler8) - } - if (slam < xvmin) { - undral = max(undral, slam + toler8) - } - slam = 0.5 * (slam + xvmin) - iterate = true - niter++ - } - } while (iterate && niter < maxiter) - if (niter >= maxiter) { - // exhausted max number of iterations - return MnParabolaPoint(xvmin, fvmin) - } - - // find worst previous point out of three and replace - val p3 = MnParabolaPoint(slam, F3) - if (p0.y() > p1.y() && p0.y() > p2.y()) { - p0 = p3 - } else if (p1.y() > p0.y() && p1.y() > p2.y()) { - p1 = p3 - } else { - p2 = p3 - } - if (F3 < fvmin) { - fvmin = F3 - xvmin = slam - } else { - if (slam > xvmin) { - overal = min(overal, slam - toler8) - } - if (slam < xvmin) { - undral = max(undral, slam + toler8) - } - } - niter++ - } while (niter < maxiter) - return MnParabolaPoint(xvmin, fvmin) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMachinePrecision.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMachinePrecision.kt deleted file mode 100644 index 161ee0c0a..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnMachinePrecision.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * Determines the relative floating point arithmetic precision. The - * setPrecision() method can be used to override Minuit's own determination, - * when the user knows that the {FCN} function value is not calculated to the - * nominal machine accuracy. - * - * @version $Id$ - * @author Darksnake - */ -class MnMachinePrecision internal constructor() { - private var theEpsMa2 = 0.0 - private var theEpsMac = 0.0 - - /** - * eps returns the smallest possible number so that 1.+eps > 1. - * @return - */ - fun eps(): Double { - return theEpsMac - } - - /** - * eps2 returns 2*sqrt(eps) - * @return - */ - fun eps2(): Double { - return theEpsMa2 - } - - /** - * override Minuit's own determination - * - * @param prec a double. - */ - fun setPrecision(prec: Double) { - theEpsMac = prec - theEpsMa2 = 2.0 * sqrt(theEpsMac) - } - - init { - setPrecision(4.0E-7) - var epstry = 0.5 - val one = 1.0 - for (i in 0..99) { - epstry *= 0.5 - val epsp1 = one + epstry - val epsbak = epsp1 - one - if (epsbak < epstry) { - setPrecision(8.0 * epstry) - break - } - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt deleted file mode 100644 index 22616a1a6..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * MnMigrad provides minimization of the function by the method of MIGRAD, the - * most efficient and complete single method, recommended for general functions, - * and the functionality for parameters interaction. It also retains the result - * from the last minimization in case the user may want to do subsequent - * minimization steps with parameter interactions in between the minimization - * requests. The minimization produces as a by-product the error matrix of the - * parameters, which is usually reliable unless warning messages are produced. - * - * @version $Id$ - * @author Darksnake - */ -class MnMigrad -/** - * construct from MultiFunction + MnUserParameterState + MnStrategy - * - * @param str a [hep.dataforge.MINUIT.MnStrategy] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param fcn a [MultiFunction] object. - */ - (fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { - private val theMinimizer: VariableMetricMinimizer = VariableMetricMinimizer() - - /** - * construct from MultiFunction + double[] for parameters and errors - * with default strategy - * - * @param err an array of double. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and errors - * - * @param stra a int. - * @param err an array of double. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, - MnUserParameterState(par, err), - MnStrategy(stra)) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters with default - * strategy - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters - * - * @param stra a int. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, - MnUserParameterState(par), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, - par, - cov, - DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - override fun minimizer(): ModularFunctionMinimizer { - return theMinimizer - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt deleted file mode 100644 index ea14a5453..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * Causes minimization of the function by the method of MIGRAD, as does the - * MnMigrad class, but switches to the SIMPLEX method if MIGRAD fails to - * converge. Constructor arguments, methods arguments and names of methods are - * the same as for MnMigrad or MnSimplex. - * - * @version $Id$ - * @author Darksnake - */ -class MnMinimize -/** - * construct from MultiFunction + MnUserParameterState + MnStrategy - * - * @param str a [hep.dataforge.MINUIT.MnStrategy] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param fcn a [MultiFunction] object. - */ - (fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { - private val theMinimizer: CombinedMinimizer = CombinedMinimizer() - - /** - * construct from MultiFunction + double[] for parameters and errors - * with default strategy - * - * @param err an array of double. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and errors - * - * @param stra a int. - * @param err an array of double. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, - MnUserParameterState(par, err), - MnStrategy(stra)) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters with default - * strategy - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters - * - * @param stra a int. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, - MnUserParameterState(par), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, - par, - cov, - DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - override fun minimizer(): ModularFunctionMinimizer { - return theMinimizer - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt deleted file mode 100644 index d49379b3b..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* -import kotlin.jvm.JvmOverloads - -/** - * API class for Minos error analysis (asymmetric errors). Minimization has to - * be done before and minimum must be valid; possibility to ask only for one - * side of the Minos error; - * - * @version $Id$ - * @author Darksnake - */ -class MnMinos(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) { - private var theFCN: MultiFunction? = null - private var theMinimum: FunctionMinimum? = null - private var theStrategy: MnStrategy? = null - - /** - * construct from FCN + minimum - * - * @param fcn a [MultiFunction] object. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - constructor(fcn: MultiFunction?, min: FunctionMinimum?) : this(fcn, min, MnApplication.DEFAULT_STRATEGY) - - /** - * construct from FCN + minimum + strategy - * - * @param stra a int. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, min: FunctionMinimum?, stra: Int) : this(fcn, min, MnStrategy(stra)) - // public MnMinos(MultiFunction fcn, MnUserParameterState state, double errDef, MnStrategy stra) { - // theFCN = fcn; - // theStrategy = stra; - // - // MinimumState minState = null; - // - // MnUserTransformation transformation = state.getTransformation(); - // - // MinimumSeed seed = new MinimumSeed(minState, transformation); - // - // theMinimum = new FunctionMinimum(seed,errDef); - // } - /** - * - * loval. - * - * @param par a int. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun loval(par: Int): MnCross { - return loval(par, 1.0) - } - - /** - * - * loval. - * - * @param par a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun loval(par: Int, errDef: Double): MnCross { - return loval(par, errDef, MnApplication.DEFAULT_MAXFCN) - } - - /** - * - * loval. - * - * @param par a int. - * @param errDef a double. - * @param maxcalls a int. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun loval(par: Int, errDef: Double, maxcalls: Int): MnCross { - var errDef = errDef - var maxcalls = maxcalls - errDef *= theMinimum!!.errorDef() - assert(theMinimum!!.isValid()) - assert(!theMinimum!!.userState().parameter(par).isFixed()) - assert(!theMinimum!!.userState().parameter(par).isConst()) - if (maxcalls == 0) { - val nvar: Int = theMinimum!!.userState().variableParameters() - maxcalls = 2 * (nvar + 1) * (200 + 100 * nvar + 5 * nvar * nvar) - } - val para = intArrayOf(par) - val upar: MnUserParameterState = theMinimum!!.userState().copy() - val err: Double = upar.error(par) - val `val`: Double = upar.value(par) - err - val xmid = doubleArrayOf(`val`) - val xdir = doubleArrayOf(-err) - val ind: Int = upar.intOfExt(par) - val m: MnAlgebraicSymMatrix = theMinimum!!.error().matrix() - val xunit: Double = sqrt(errDef / err) - for (i in 0 until m.nrow()) { - if (i == ind) { - continue - } - val xdev: Double = xunit * m[ind, i] - val ext: Int = upar.extOfInt(i) - upar.setValue(ext, upar.value(ext) - xdev) - } - upar.fix(par) - upar.setValue(par, `val`) - val toler = 0.1 - val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef) - val aopt: MnCross = cross.cross(para, xmid, xdir, toler, maxcalls) - if (aopt.atLimit()) { - MINUITPlugin.logStatic("MnMinos parameter $par is at lower limit.") - } - if (aopt.atMaxFcn()) { - MINUITPlugin.logStatic("MnMinos maximum number of function calls exceeded for parameter $par") - } - if (aopt.newMinimum()) { - MINUITPlugin.logStatic("MnMinos new minimum found while looking for parameter $par") - } - if (!aopt.isValid()) { - MINUITPlugin.logStatic("MnMinos could not find lower value for parameter $par.") - } - return aopt - } - /** - * calculate one side (negative or positive error) of the parameter - * - * @param maxcalls a int. - * @param par a int. - * @param errDef a double. - * @return a double. - */ - /** - * - * lower. - * - * @param par a int. - * @param errDef a double. - * @return a double. - */ - /** - * - * lower. - * - * @param par a int. - * @return a double. - */ - @JvmOverloads - fun lower(par: Int, errDef: Double = 1.0, maxcalls: Int = MnApplication.DEFAULT_MAXFCN): Double { - val upar: MnUserParameterState = theMinimum!!.userState() - val err: Double = theMinimum!!.userState().error(par) - val aopt: MnCross = loval(par, errDef, maxcalls) - return if (aopt.isValid()) -1.0 * err * (1.0 + aopt.value()) else if (aopt.atLimit()) upar.parameter(par) - .lowerLimit() else upar.value(par) - } - - /** - * - * minos. - * - * @param par a int. - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun minos(par: Int): MinosError { - return minos(par, 1.0) - } - - /** - * - * minos. - * - * @param par a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun minos(par: Int, errDef: Double): MinosError { - return minos(par, errDef, MnApplication.DEFAULT_MAXFCN) - } - - /** - * Causes a MINOS error analysis to be performed on the parameter whose - * number is specified. MINOS errors may be expensive to calculate, but are - * very reliable since they take account of non-linearities in the problem - * as well as parameter correlations, and are in general asymmetric. - * - * @param maxcalls Specifies the (approximate) maximum number of function - * calls per parameter requested, after which the calculation will be - * stopped for that parameter. - * @param errDef a double. - * @param par a int. - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun minos(par: Int, errDef: Double, maxcalls: Int): MinosError { - assert(theMinimum!!.isValid()) - assert(!theMinimum!!.userState().parameter(par).isFixed()) - assert(!theMinimum!!.userState().parameter(par).isConst()) - val up: MnCross = upval(par, errDef, maxcalls) - val lo: MnCross = loval(par, errDef, maxcalls) - return MinosError(par, theMinimum!!.userState().value(par), lo, up) - } - - /** - * - * range. - * - * @param par a int. - * @return - */ - fun range(par: Int): Range { - return range(par, 1.0) - } - - /** - * - * range. - * - * @param par a int. - * @param errDef a double. - * @return - */ - fun range(par: Int, errDef: Double): Range { - return range(par, errDef, MnApplication.DEFAULT_MAXFCN) - } - - /** - * Causes a MINOS error analysis for external parameter n. - * - * @param maxcalls a int. - * @param errDef a double. - * @return The lower and upper bounds of parameter - * @param par a int. - */ - fun range(par: Int, errDef: Double, maxcalls: Int): Range { - val mnerr: MinosError = minos(par, errDef, maxcalls) - return mnerr.range() - } - /** - * - * upper. - * - * @param par a int. - * @param errDef a double. - * @param maxcalls a int. - * @return a double. - */ - /** - * - * upper. - * - * @param par a int. - * @param errDef a double. - * @return a double. - */ - /** - * - * upper. - * - * @param par a int. - * @return a double. - */ - @JvmOverloads - fun upper(par: Int, errDef: Double = 1.0, maxcalls: Int = MnApplication.DEFAULT_MAXFCN): Double { - val upar: MnUserParameterState = theMinimum!!.userState() - val err: Double = theMinimum!!.userState().error(par) - val aopt: MnCross = upval(par, errDef, maxcalls) - return if (aopt.isValid()) err * (1.0 + aopt.value()) else if (aopt.atLimit()) upar.parameter(par) - .upperLimit() else upar.value(par) - } - - /** - * - * upval. - * - * @param par a int. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun upval(par: Int): MnCross { - return upval(par, 1.0) - } - - /** - * - * upval. - * - * @param par a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun upval(par: Int, errDef: Double): MnCross { - return upval(par, errDef, MnApplication.DEFAULT_MAXFCN) - } - - /** - * - * upval. - * - * @param par a int. - * @param errDef a double. - * @param maxcalls a int. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun upval(par: Int, errDef: Double, maxcalls: Int): MnCross { - var errDef = errDef - var maxcalls = maxcalls - errDef *= theMinimum!!.errorDef() - assert(theMinimum!!.isValid()) - assert(!theMinimum!!.userState().parameter(par).isFixed()) - assert(!theMinimum!!.userState().parameter(par).isConst()) - if (maxcalls == 0) { - val nvar: Int = theMinimum!!.userState().variableParameters() - maxcalls = 2 * (nvar + 1) * (200 + 100 * nvar + 5 * nvar * nvar) - } - val para = intArrayOf(par) - val upar: MnUserParameterState = theMinimum!!.userState().copy() - val err: Double = upar.error(par) - val `val`: Double = upar.value(par) + err - val xmid = doubleArrayOf(`val`) - val xdir = doubleArrayOf(err) - val ind: Int = upar.intOfExt(par) - val m: MnAlgebraicSymMatrix = theMinimum!!.error().matrix() - val xunit: Double = sqrt(errDef / err) - for (i in 0 until m.nrow()) { - if (i == ind) { - continue - } - val xdev: Double = xunit * m[ind, i] - val ext: Int = upar.extOfInt(i) - upar.setValue(ext, upar.value(ext) + xdev) - } - upar.fix(par) - upar.setValue(par, `val`) - val toler = 0.1 - val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef) - val aopt: MnCross = cross.cross(para, xmid, xdir, toler, maxcalls) - if (aopt.atLimit()) { - MINUITPlugin.logStatic("MnMinos parameter $par is at upper limit.") - } - if (aopt.atMaxFcn()) { - MINUITPlugin.logStatic("MnMinos maximum number of function calls exceeded for parameter $par") - } - if (aopt.newMinimum()) { - MINUITPlugin.logStatic("MnMinos new minimum found while looking for parameter $par") - } - if (!aopt.isValid()) { - MINUITPlugin.logStatic("MnMinos could not find upper value for parameter $par.") - } - return aopt - } - - /** - * construct from FCN + minimum + strategy - * - * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - * @param fcn a [MultiFunction] object. - */ - init { - theFCN = fcn - theMinimum = min - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnParabola.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParabola.kt deleted file mode 100644 index a0a56dedd..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnParabola.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * parabola = a*xx + b*x + c - * - * @version $Id$ - */ -internal class MnParabola(private val theA: Double, private val theB: Double, private val theC: Double) { - fun a(): Double { - return theA - } - - fun b(): Double { - return theB - } - - fun c(): Double { - return theC - } - - fun min(): Double { - return -theB / (2.0 * theA) - } - - fun x_neg(y: Double): Double { - return -sqrt(y / theA + min() * min() - theC / theA) + min() - } - - fun x_pos(y: Double): Double { - return sqrt(y / theA + min() * min() - theC / theA) + min() - } - - fun y(x: Double): Double { - return theA * x * x + theB * x + theC - } - - fun ymin(): Double { - return -theB * theB / (4.0 * theA) + theC - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaFactory.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaFactory.kt deleted file mode 100644 index f45d2b9c9..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaFactory.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal object MnParabolaFactory { - fun create(p1: MnParabolaPoint, p2: MnParabolaPoint, p3: MnParabolaPoint): MnParabola { - var x1: Double = p1.x() - var x2: Double = p2.x() - var x3: Double = p3.x() - val dx12 = x1 - x2 - val dx13 = x1 - x3 - val dx23 = x2 - x3 - val xm = (x1 + x2 + x3) / 3.0 - x1 -= xm - x2 -= xm - x3 -= xm - val y1: Double = p1.y() - val y2: Double = p2.y() - val y3: Double = p3.y() - val a = y1 / (dx12 * dx13) - y2 / (dx12 * dx23) + y3 / (dx13 * dx23) - var b = -y1 * (x2 + x3) / (dx12 * dx13) + y2 * (x1 + x3) / (dx12 * dx23) - y3 * (x1 + x2) / (dx13 * dx23) - var c = y1 - a * x1 * x1 - b * x1 - c += xm * (xm * a - b) - b -= 2.0 * xm * a - return MnParabola(a, b, c) - } - - fun create(p1: MnParabolaPoint, dxdy1: Double, p2: MnParabolaPoint): MnParabola { - val x1: Double = p1.x() - val xx1 = x1 * x1 - val x2: Double = p2.x() - val xx2 = x2 * x2 - val y1: Double = p1.y() - val y12: Double = p1.y() - p2.y() - val det = xx1 - xx2 - 2.0 * x1 * (x1 - x2) - val a = -(y12 + (x2 - x1) * dxdy1) / det - val b = -(-2.0 * x1 * y12 + (xx1 - xx2) * dxdy1) / det - val c = y1 - a * xx1 - b * x1 - return MnParabola(a, b, c) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaPoint.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaPoint.kt deleted file mode 100644 index 858e010e6..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaPoint.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class MnParabolaPoint(private val theX: Double, private val theY: Double) { - fun x(): Double { - return theX - } - - fun y(): Double { - return theY - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnParameterScan.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParameterScan.kt deleted file mode 100644 index 7791c20e8..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnParameterScan.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * Scans the values of FCN as a function of one parameter and retains the best - * function and parameter values found - * - * @version $Id$ - */ -internal class MnParameterScan { - private var theAmin: Double - private var theFCN: MultiFunction? - private var theParameters: MnUserParameters - - constructor(fcn: MultiFunction, par: MnUserParameters) { - theFCN = fcn - theParameters = par - theAmin = fcn.value(par.params()) - } - - constructor(fcn: MultiFunction?, par: MnUserParameters, fval: Double) { - theFCN = fcn - theParameters = par - theAmin = fval - } - - fun fval(): Double { - return theAmin - } - - fun parameters(): MnUserParameters { - return theParameters - } - - fun scan(par: Int): List { - return scan(par, 41) - } - - fun scan(par: Int, maxsteps: Int): List { - return scan(par, maxsteps, 0.0, 0.0) - } - - /** - * returns pairs of (x,y) points, x=parameter value, y=function value of FCN - * @param high - * @return - */ - fun scan(par: Int, maxsteps: Int, low: Double, high: Double): List { - var maxsteps = maxsteps - var low = low - var high = high - if (maxsteps > 101) { - maxsteps = 101 - } - val result: MutableList = java.util.ArrayList(maxsteps + 1) - val params: DoubleArray = theParameters.params() - result.add(Range(params[par], theAmin)) - if (low > high) { - return result - } - if (maxsteps < 2) { - return result - } - if (low == 0.0 && high == 0.0) { - low = params[par] - 2.0 * theParameters.error(par) - high = params[par] + 2.0 * theParameters.error(par) - } - if (low == 0.0 && high == 0.0 && theParameters.parameter(par).hasLimits()) { - if (theParameters.parameter(par).hasLowerLimit()) { - low = theParameters.parameter(par).lowerLimit() - } - if (theParameters.parameter(par).hasUpperLimit()) { - high = theParameters.parameter(par).upperLimit() - } - } - if (theParameters.parameter(par).hasLimits()) { - if (theParameters.parameter(par).hasLowerLimit()) { - low = max(low, theParameters.parameter(par).lowerLimit()) - } - if (theParameters.parameter(par).hasUpperLimit()) { - high = min(high, theParameters.parameter(par).upperLimit()) - } - } - val x0 = low - val stp = (high - low) / (maxsteps - 1.0) - for (i in 0 until maxsteps) { - params[par] = x0 + i.toDouble() * stp - val fval: Double = theFCN.value(params) - if (fval < theAmin) { - theParameters.setValue(par, params[par]) - theAmin = fval - } - result.add(Range(params[par], fval)) - } - return result - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnPlot.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnPlot.kt deleted file mode 100644 index 656dd8d35..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnPlot.kt +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import java.lang.StringBuffer -import kotlin.jvm.JvmOverloads - -/** - * MnPlot produces a text-screen graphical output of (x,y) points. E.g. from - * Scan or Contours. - * - * @version $Id$ - * @author Darksnake - */ -class MnPlot @JvmOverloads constructor(private val thePageWidth: Int = 80, private val thePageLength: Int = 30) { - private var bh = 0.0 - private var bl = 0.0 - private var bwid = 0.0 - private var nb = 0 - fun length(): Int { - return thePageLength - } - - private fun mnbins(a1: Double, a2: Double, naa: Int) { - - //*-*-*-*-*-*-*-*-*-*-*Compute reasonable histogram intervals*-*-*-*-*-*-*-*-* - //*-* ====================================== - //*-* Function TO DETERMINE REASONABLE HISTOGRAM INTERVALS - //*-* GIVEN ABSOLUTE UPPER AND LOWER BOUNDS A1 AND A2 - //*-* AND DESIRED MAXIMUM NUMBER OF BINS NAA - //*-* PROGRAM MAKES REASONABLE BINNING FROM BL TO BH OF WIDTH BWID - //*-* F. JAMES, AUGUST, 1974 , stolen for Minuit, 1988 - //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* - - /* Local variables */ - var awid: Double - var ah: Double - var sigfig: Double - var sigrnd: Double - var alb: Double - var kwid: Int - var lwid: Int - var na = 0 - var log_: Int - val al: Double = if (a1 < a2) a1 else a2 - ah = if (a1 > a2) a1 else a2 - if (al == ah) { - ah = al + 1 - } - - //*-*- IF NAA .EQ. -1 , PROGRAM USES BWID INPUT FROM CALLING ROUTINE - var skip = naa == -1 && bwid > 0 - if (!skip) { - na = naa - 1 - if (na < 1) { - na = 1 - } - } - while (true) { - if (!skip) { - //*-*- GET NOMINAL BIN WIDTH IN EXPON FORM - awid = (ah - al) / na.toDouble() - log_ = log10(awid) - if (awid <= 1) { - --log_ - } - sigfig = awid * pow(10.0, -log_.toDouble()) - //*-*- ROUND MANTISSA UP TO 2, 2.5, 5, OR 10 - if (sigfig <= 2) { - sigrnd = 2.0 - } else if (sigfig <= 2.5) { - sigrnd = 2.5 - } else if (sigfig <= 5) { - sigrnd = 5.0 - } else { - sigrnd = 1.0 - ++log_ - } - bwid = sigrnd * pow(10.0, log_.toDouble()) - } - alb = al / bwid - lwid = alb.toInt() - if (alb < 0) { - --lwid - } - bl = bwid * lwid.toDouble() - alb = ah / bwid + 1 - kwid = alb.toInt() - if (alb < 0) { - --kwid - } - bh = bwid * kwid.toDouble() - nb = kwid - lwid - if (naa <= 5) { - if (naa == -1) { - return - } - //*-*- REQUEST FOR ONE BIN IS DIFFICULT CASE - if (naa > 1 || nb == 1) { - return - } - bwid *= 2.0 - nb = 1 - return - } - if (nb shl 1 != naa) { - return - } - ++na - skip = false - continue - } - } - - private fun mnplot(xpt: DoubleArray, ypt: DoubleArray, chpt: StringBuffer, nxypt: Int, npagwd: Int, npagln: Int) { - //*-*-*-*Plots points in array xypt onto one page with labelled axes*-*-*-*-* - //*-* =========================================================== - //*-* NXYPT is the number of points to be plotted - //*-* XPT(I) = x-coord. of ith point - //*-* YPT(I) = y-coord. of ith point - //*-* CHPT(I) = character to be plotted at this position - //*-* the input point arrays XPT, YPT, CHPT are destroyed. - //*-* - //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* - - /* Local variables */ - var xmin: Double - var xmax: Double - var ymax: Double - var savx: Double - var savy: Double - var yprt: Double - var xbest: Double - var ybest: Double - val xvalus = DoubleArray(12) - val any: Double - val iten: Int - var j: Int - var k: Int - var maxnx: Int - var maxny: Int - var iquit: Int - var ni: Int - var linodd: Int - var ibk: Int - var isp1: Int - var ks: Int - var ix: Int - var overpr: Boolean - val cline = StringBuffer(npagwd) - for (ii in 0 until npagwd) { - cline.append(' ') - } - var chsav: Char - val chbest: Char - - /* Function Body */ - //*-* Computing MIN - maxnx = if (npagwd - 20 < 100) npagwd - 20 else 100 - if (maxnx < 10) { - maxnx = 10 - } - maxny = npagln - if (maxny < 10) { - maxny = 10 - } - if (nxypt <= 1) { - return - } - xbest = xpt[0] - ybest = ypt[0] - chbest = chpt.get(0) - //*-*- order the points by decreasing y - val km1: Int = nxypt - 1 - var i: Int = 1 - while (i <= km1) { - iquit = 0 - ni = nxypt - i - j = 1 - while (j <= ni) { - if (ypt[j - 1] > ypt[j]) { - ++j - continue - } - savx = xpt[j - 1] - xpt[j - 1] = xpt[j] - xpt[j] = savx - savy = ypt[j - 1] - ypt[j - 1] = ypt[j] - ypt[j] = savy - chsav = chpt.get(j - 1) - chpt.setCharAt(j - 1, chpt.get(j)) - chpt.setCharAt(j, chsav) - iquit = 1 - ++j - } - if (iquit == 0) { - break - } - ++i - } - //*-*- find extreme values - xmax = xpt[0] - xmin = xmax - i = 1 - while (i <= nxypt) { - if (xpt[i - 1] > xmax) { - xmax = xpt[i - 1] - } - if (xpt[i - 1] < xmin) { - xmin = xpt[i - 1] - } - ++i - } - val dxx: Double = (xmax - xmin) * .001 - xmax += dxx - xmin -= dxx - mnbins(xmin, xmax, maxnx) - xmin = bl - xmax = bh - var nx: Int = nb - val bwidx: Double = bwid - ymax = ypt[0] - var ymin: Double = ypt[nxypt - 1] - if (ymax == ymin) { - ymax = ymin + 1 - } - val dyy: Double = (ymax - ymin) * .001 - ymax += dyy - ymin -= dyy - mnbins(ymin, ymax, maxny) - ymin = bl - ymax = bh - var ny: Int = nb - val bwidy: Double = bwid - any = ny.toDouble() - //*-*- if first point is blank, it is an 'origin' - if (chbest != ' ') { - xbest = (xmax + xmin) * .5 - ybest = (ymax + ymin) * .5 - } - //*-*- find scale constants - val ax: Double = 1 / bwidx - val ay: Double = 1 / bwidy - val bx: Double = -ax * xmin + 2 - val by: Double = -ay * ymin - 2 - //*-*- convert points to grid positions - i = 1 - while (i <= nxypt) { - xpt[i - 1] = ax * xpt[i - 1] + bx - ypt[i - 1] = any - ay * ypt[i - 1] - by - ++i - } - val nxbest: Int = (ax * xbest + bx).toInt() - val nybest: Int = (any - ay * ybest - by).toInt() - //*-*- print the points - ny += 2 - nx += 2 - isp1 = 1 - linodd = 1 - overpr = false - i = 1 - while (i <= ny) { - ibk = 1 - while (ibk <= nx) { - cline.setCharAt(ibk - 1, ' ') - ++ibk - } - // cline.setCharAt(nx,'\0'); - // cline.setCharAt(nx+1,'\0'); - cline.setCharAt(0, '.') - cline.setCharAt(nx - 1, '.') - cline.setCharAt(nxbest - 1, '.') - if (i == 1 || i == nybest || i == ny) { - j = 1 - while (j <= nx) { - cline.setCharAt(j - 1, '.') - ++j - } - } - yprt = ymax - (i - 1.0) * bwidy - var isplset = false - if (isp1 <= nxypt) { - //*-*- find the points to be plotted on this line - k = isp1 - while (k <= nxypt) { - ks = ypt[k - 1].toInt() - if (ks > i) { - isp1 = k - isplset = true - break - } - ix = xpt[k - 1].toInt() - if (cline.get(ix - 1) != '.' && cline.get(ix - 1) != ' ') { - if (cline.get(ix - 1) == chpt.get(k - 1)) { - ++k - continue - } - overpr = true - //*-*- OVERPR is true if one or more positions contains more than - //*-*- one point - cline.setCharAt(ix - 1, '&') - ++k - continue - } - cline.setCharAt(ix - 1, chpt.get(k - 1)) - ++k - } - if (!isplset) { - isp1 = nxypt + 1 - } - } - if (linodd != 1 && i != ny) { - linodd = 1 - java.lang.System.out.printf(" %s", cline.substring(0, 60)) - } else { - java.lang.System.out.printf(" %14.7g ..%s", yprt, cline.substring(0, 60)) - linodd = 0 - } - println() - ++i - } - //*-*- print labels on x-axis every ten columns - ibk = 1 - while (ibk <= nx) { - cline.setCharAt(ibk - 1, ' ') - if (ibk % 10 == 1) { - cline.setCharAt(ibk - 1, '/') - } - ++ibk - } - java.lang.System.out.printf(" %s", cline) - java.lang.System.out.printf("\n") - ibk = 1 - while (ibk <= 12) { - xvalus[ibk - 1] = xmin + (ibk - 1.0) * 10 * bwidx - ++ibk - } - java.lang.System.out.printf(" ") - iten = (nx + 9) / 10 - ibk = 1 - while (ibk <= iten) { - java.lang.System.out.printf(" %9.4g", xvalus[ibk - 1]) - ++ibk - } - java.lang.System.out.printf("\n") - if (overpr) { - val chmess = " Overprint character is &" - java.lang.System.out.printf(" ONE COLUMN=%13.7g%s", bwidx, chmess) - } else { - val chmess = " " - java.lang.System.out.printf(" ONE COLUMN=%13.7g%s", bwidx, chmess) - } - println() - } - - /** - * - * plot. - * - * @param points a [List] object. - */ - fun plot(points: List) { - val x = DoubleArray(points.size) - val y = DoubleArray(points.size) - val chpt = StringBuffer(points.size) - for ((i, ipoint) in points.withIndex()) { - x[i] = ipoint.getFirst() - y[i] = ipoint.getSecond() - chpt.append('*') - } - mnplot(x, y, chpt, points.size, width(), length()) - } - - /** - * - * plot. - * - * @param xmin a double. - * @param ymin a double. - * @param points a [List] object. - */ - fun plot(xmin: Double, ymin: Double, points: List) { - val x = DoubleArray(points.size + 2) - x[0] = xmin - x[1] = xmin - val y = DoubleArray(points.size + 2) - y[0] = ymin - y[1] = ymin - val chpt = StringBuffer(points.size + 2) - chpt.append(' ') - chpt.append('X') - var i = 2 - for (ipoint in points) { - x[i] = ipoint.getFirst() - y[i] = ipoint.getSecond() - chpt.append('*') - i++ - } - mnplot(x, y, chpt, points.size + 2, width(), length()) - } - - fun width(): Int { - return thePageWidth - } - /** - * - * Constructor for MnPlot. - * - * @param thePageWidth a int. - * @param thePageLength a int. - */ - /** - * - * Constructor for MnPlot. - */ - init { - if (thePageWidth > 120) { - thePageWidth = 120 - } - if (thePageLength > 56) { - thePageLength = 56 - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnPosDef.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnPosDef.kt deleted file mode 100644 index e8d29c8e4..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnPosDef.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin - -/** - * - * @version $Id$ - */ -internal object MnPosDef { - fun test(st: MinimumState, prec: MnMachinePrecision): MinimumState { - val err: MinimumError = test(st.error(), prec) - return MinimumState(st.parameters(), err, st.gradient(), st.edm(), st.nfcn()) - } - - fun test(e: MinimumError, prec: MnMachinePrecision): MinimumError { - val err: MnAlgebraicSymMatrix = e.invHessian().copy() - if (err.size() === 1 && err[0, 0] < prec.eps()) { - err[0, 0] = 1.0 - return MinimumError(err, MnMadePosDef()) - } - if (err.size() === 1 && err[0, 0] > prec.eps()) { - return e - } - // standardDiviation::cout<<"MnPosDef init matrix= "< 0.0) { - os.printf(" limited || %10g", ipar.value()) - if (abs(ipar.value() - ipar.lowerLimit()) < par.precision().eps2()) { - os.print("* ") - atLoLim = true - } - if (abs(ipar.value() - ipar.upperLimit()) < par.precision().eps2()) { - os.print("**") - atHiLim = true - } - os.printf(" || %10g\n", ipar.error()) - } else { - os.printf(" free || %10g || no\n", ipar.value()) - } - } else { - if (ipar.error() > 0.0) { - os.printf(" free || %10g || %10g\n", ipar.value(), ipar.error()) - } else { - os.printf(" free || %10g || no\n", ipar.value()) - } - } - } - os.println() - if (atLoLim) { - os.print("* parameter is at lower limit") - } - if (atHiLim) { - os.print("** parameter is at upper limit") - } - os.println() - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param matrix a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun print(os: PrintWriter, matrix: MnUserCovariance) { - os.println() - os.println("MnUserCovariance: ") - run { - os.println() - val n: Int = matrix.nrow() - for (i in 0 until n) { - for (j in 0 until n) { - os.printf("%10g ", matrix[i, j]) - } - os.println() - } - } - os.println() - os.println("MnUserCovariance parameter correlations: ") - run { - os.println() - val n: Int = matrix.nrow() - for (i in 0 until n) { - val di: Double = matrix[i, i] - for (j in 0 until n) { - val dj: Double = matrix[j, j] - os.printf("%g ", matrix[i, j] / sqrt(abs(di * dj))) - } - os.println() - } - } - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param coeff a [hep.dataforge.MINUIT.MnGlobalCorrelationCoeff] object. - */ - fun print(os: PrintWriter, coeff: MnGlobalCorrelationCoeff) { - os.println() - os.println("MnGlobalCorrelationCoeff: ") - run { - os.println() - for (i in 0 until coeff.globalCC().length) { - os.printf("%g\n", coeff.globalCC()[i]) - } - } - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param state a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun print(os: PrintWriter, state: MnUserParameterState) { - os.println() - if (!state.isValid()) { - os.println() - os.println("WARNING: MnUserParameterState is not valid.") - os.println() - } - os.println("# of function calls: " + state.nfcn()) - os.println("function value: " + state.fval()) - os.println("expected distance to the minimum (edm): " + state.edm()) - os.println("external parameters: " + state.parameters()) - if (state.hasCovariance()) { - os.println("covariance matrix: " + state.covariance()) - } - if (state.hasGlobalCC()) { - os.println("global correlation coefficients : " + state.globalCC()) - } - if (!state.isValid()) { - os.println("WARNING: MnUserParameterState is not valid.") - } - os.println() - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param me a [hep.dataforge.MINUIT.MinosError] object. - */ - fun print(os: PrintWriter, me: MinosError) { - os.println() - os.printf("Minos # of function calls: %d\n", me.nfcn()) - if (!me.isValid()) { - os.println("Minos error is not valid.") - } - if (!me.lowerValid()) { - os.println("lower Minos error is not valid.") - } - if (!me.upperValid()) { - os.println("upper Minos error is not valid.") - } - if (me.atLowerLimit()) { - os.println("Minos error is lower limit of parameter " + me.parameter()) - } - if (me.atUpperLimit()) { - os.println("Minos error is upper limit of parameter " + me.parameter()) - } - if (me.atLowerMaxFcn()) { - os.println("Minos number of function calls for lower error exhausted.") - } - if (me.atUpperMaxFcn()) { - os.println("Minos number of function calls for upper error exhausted.") - } - if (me.lowerNewMin()) { - os.println("Minos found a new minimum in negative direction.") - os.println(me.lowerState()) - } - if (me.upperNewMin()) { - os.println("Minos found a new minimum in positive direction.") - os.println(me.upperState()) - } - os.println("# ext. || name || value@min || negative || positive ") - os.printf("%4d||%10s||%10g||%10g||%10g\n", - me.parameter(), - me.lowerState().name(me.parameter()), - me.min(), - me.lower(), - me.upper()) - os.println() - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param ce a [hep.dataforge.MINUIT.ContoursError] object. - */ - fun print(os: PrintWriter, ce: ContoursError) { - os.println() - os.println("Contours # of function calls: " + ce.nfcn()) - os.println("MinosError in x: ") - os.println(ce.xMinosError()) - os.println("MinosError in y: ") - os.println(ce.yMinosError()) - val plot = MnPlot() - plot.plot(ce.xmin(), ce.ymin(), ce.points()) - for ((i, ipoint) in ce.points().withIndex()) { - os.printf("%d %10g %10g\n", i, ipoint.getFirst(), ipoint.getSecond()) - } - os.println() - } - - fun toString(x: RealVector): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnAlgebraicSymMatrix?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(min: FunctionMinimum?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, min) } - return writer.toString() - } - - fun toString(x: MinimumState?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnUserParameters?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnUserCovariance?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnGlobalCorrelationCoeff?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnUserParameterState?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MinosError?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: ContoursError?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt deleted file mode 100644 index 63e565b4f..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * MnScan scans the value of the user function by varying one parameter. It is - * sometimes useful for debugging the user function or finding a reasonable - * starting point. - * construct from MultiFunction + MnUserParameterState + MnStrategy - * - * @param str a [hep.dataforge.MINUIT.MnStrategy] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param fcn a [MultiFunction] object. - * @version $Id$ - * @author Darksnake - */ -class MnScan(fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { - private val theMinimizer: ScanMinimizer = ScanMinimizer() - - /** - * construct from MultiFunction + double[] for parameters and errors - * with default strategy - * - * @param err an array of double. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and errors - * - * @param stra a int. - * @param err an array of double. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, - MnUserParameterState(par, err), - MnStrategy(stra)) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters with default - * strategy - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters - * - * @param stra a int. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, - MnUserParameterState(par), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, - par, - cov, - DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - override fun minimizer(): ModularFunctionMinimizer { - return theMinimizer - } - - /** - * - * scan. - * - * @param par a int. - * @return a [List] object. - */ - fun scan(par: Int): List { - return scan(par, 41) - } - - /** - * - * scan. - * - * @param par a int. - * @param maxsteps a int. - * @return a [List] object. - */ - fun scan(par: Int, maxsteps: Int): List { - return scan(par, maxsteps, 0.0, 0.0) - } - - /** - * Scans the value of the user function by varying parameter number par, - * leaving all other parameters fixed at the current value. If par is not - * specified, all variable parameters are scanned in sequence. The number of - * points npoints in the scan is 40 by default, and cannot exceed 100. The - * range of the scan is by default 2 standard deviations on each side of the - * current best value, but can be specified as from low to high. After each - * scan, if a new minimum is found, the best parameter values are retained - * as start values for future scans or minimizations. The curve resulting - * from each scan can be plotted on the output terminal using MnPlot in - * order to show the approximate behaviour of the function. - * - * @param high a double. - * @param par a int. - * @param maxsteps a int. - * @param low a double. - * @return a [List] object. - */ - fun scan(par: Int, maxsteps: Int, low: Double, high: Double): List { - val scan = MnParameterScan(theFCN, theState.parameters()) - var amin: Double = scan.fval() - val result: List = scan.scan(par, maxsteps, low, high) - if (scan.fval() < amin) { - theState.setValue(par, scan.parameters().value(par)) - amin = scan.fval() - } - return result - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt deleted file mode 100644 index a42edf4f1..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class MnSeedGenerator : MinimumSeedGenerator { - /** {@inheritDoc} */ - fun generate(fcn: MnFcn, gc: GradientCalculator, st: MnUserParameterState, stra: MnStrategy): MinimumSeed { - val n: Int = st.variableParameters() - val prec: MnMachinePrecision = st.precision() - - // initial starting values - val x: RealVector = ArrayRealVector(n) - for (i in 0 until n) { - x.setEntry(i, st.intParameters()[i]) - } - val fcnmin: Double = fcn.value(x) - val pa = MinimumParameters(x, fcnmin) - val dgrad: FunctionGradient - if (gc is AnalyticalGradientCalculator) { - val igc = InitialGradientCalculator(fcn, st.getTransformation(), stra) - val tmp: FunctionGradient = igc.gradient(pa) - val grd: FunctionGradient = gc.gradient(pa) - dgrad = FunctionGradient(grd.getGradient(), tmp.getGradientDerivative(), tmp.getStep()) - if (gc.checkGradient()) { - val good = true - val hgc = HessianGradientCalculator(fcn, st.getTransformation(), MnStrategy(2)) - val hgrd: Pair = hgc.deltaGradient(pa, dgrad) - for (i in 0 until n) { - val provided: Double = grd.getGradient().getEntry(i) - val calculated: Double = hgrd.getFirst().getGradient().getEntry(i) - val delta: Double = hgrd.getSecond().getEntry(i) - if (abs(calculated - provided) > delta) { - MINUITPlugin.logStatic("" - + "gradient discrepancy of external parameter \"%d\" " - + "(internal parameter \"%d\") too large. Expected: \"%f\", provided: \"%f\"", - st.getTransformation().extOfInt(i), i, provided, calculated) - -// -// MINUITPlugin.logStatic("gradient discrepancy of external parameter " -// + st.getTransformation().extOfInt(i) -// + " (internal parameter " + i + ") too large."); -// good = false; - } - } - if (!good) { - MINUITPlugin.logStatic("Minuit does not accept user specified gradient.") - // assert(good); - } - } - } else { - dgrad = gc.gradient(pa) - } - val mat = MnAlgebraicSymMatrix(n) - var dcovar = 1.0 - if (st.hasCovariance()) { - for (i in 0 until n) { - for (j in i until n) { - mat[i, j] = st.intCovariance()[i, j] - } - } - dcovar = 0.0 - } else { - for (i in 0 until n) { - mat[i, i] = if (abs(dgrad.getGradientDerivative() - .getEntry(i)) > prec.eps2() - ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0 - } - } - val err = MinimumError(mat, dcovar) - val edm: Double = VariableMetricEDMEstimator().estimate(dgrad, err) - var state = MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()) - if (NegativeG2LineSearch.hasNegativeG2(dgrad, prec)) { - state = if (gc is AnalyticalGradientCalculator) { - val ngc = Numerical2PGradientCalculator(fcn, st.getTransformation(), stra) - NegativeG2LineSearch.search(fcn, state, ngc, prec) - } else { - NegativeG2LineSearch.search(fcn, state, gc, prec) - } - } - if (stra.strategy() === 2 && !st.hasCovariance()) { - //calculate full 2nd derivative - val tmp: MinimumState = MnHesse(stra).calculate(fcn, state, st.getTransformation(), 0) - return MinimumSeed(tmp, st.getTransformation()) - } - return MinimumSeed(state, st.getTransformation()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt deleted file mode 100644 index b00745f26..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * SIMPLEX is a function minimization method using the simplex method of Nelder - * and Mead. MnSimplex provides minimization of the function by the method of - * SIMPLEX and the functionality for parameters interaction. It also retains the - * result from the last minimization in case the user may want to do subsequent - * minimization steps with parameter interactions in between the minimization - * requests. As SIMPLEX is a stepping method it does not produce a covariance - * matrix. - * - * @version $Id$ - * @author Darksnake - */ -class MnSimplex -/** - * construct from MultiFunction + MnUserParameterState + MnStrategy - * - * @param str a [hep.dataforge.MINUIT.MnStrategy] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param fcn a [MultiFunction] object. - */ - (fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { - private val theMinimizer: SimplexMinimizer = SimplexMinimizer() - - /** - * construct from MultiFunction + double[] for parameters and errors - * with default strategy - * - * @param err an array of double. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and errors - * - * @param stra a int. - * @param err an array of double. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, - MnUserParameterState(par, err), - MnStrategy(stra)) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters with default - * strategy - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters - * - * @param stra a int. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, - MnUserParameterState(par), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, - par, - cov, - DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** {@inheritDoc} */ - override fun minimizer(): ModularFunctionMinimizer { - return theMinimizer - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnStrategy.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnStrategy.kt deleted file mode 100644 index 31b894665..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnStrategy.kt +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * API class for defining three levels of strategies: low (0), medium (1), high - * (2). - * - * - * At many places in the analysis of the FCN (the user provided function), - * MINUIT must decide whether to be safe and waste a few function calls - * in order to know where it is, or to be fast and attempt to get the - * requested results with the fewest possible calls at a certain risk of not - * obtaining the precision desired by the user. In order to allow the user to - * infuence these decisions, the MnStrategy class allows the user to control - * different settings. MnStrategy can be instantiated with three different - * minimization quality levels for low (0), medium (1) and high (2) quality. - * Default settings for iteration cycles and tolerances are initialized then. - * - * - * The default setting is set for medium quality. Value 0 (low) indicates to - * MINUIT that it should economize function calls; it is intended for cases - * where there are many variable parameters and/or the function takes a long - * time to calculate and/or the user is not interested in very precise values - * for parameter errors. On the other hand, value 2 (high) indicates that MINUIT - * is allowed to waste function calls in order to be sure that all values are - * precise; it is it is intended for cases where the function is evaluated in a - * relatively short time and/or where the parameter errors must be calculated - * reliably. - * - * In addition all constants set in MnStrategy can be changed individually by - * the user, e.g. the number of iteration cycles in the numerical gradient. - * - * - * - * - * Acts on: Migrad (behavioural), Minos (lowers strategy by 1 for Minos-own - * minimization), Hesse (iterations), Numerical2PDerivative (iterations) - * - * @author Darksnake - * @version $Id$ - */ -class MnStrategy { - private var theGradNCyc = 0 - private var theGradTlr = 0.0 - private var theGradTlrStp = 0.0 - private var theHessGradNCyc = 0 - - //default strategy - private var theHessNCyc = 0 - private var theHessTlrG2 = 0.0 - private var theHessTlrStp = 0.0 - private var theStrategy = 0 - - /** - * Creates a MnStrategy object with the default strategy (medium) - */ - constructor() { - setMediumStrategy() - } - //user defined strategy (0, 1, >=2) - /** - * Creates a MnStrategy object with the user specified strategy. - * - * @param stra The use defined strategy, 0=low, 1 medium, 2=high. - */ - constructor(stra: Int) { - if (stra == 0) { - setLowStrategy() - } else if (stra == 1) { - setMediumStrategy() - } else { - setHighStrategy() - } - } - - /** - * - * gradientNCycles. - * - * @return a int. - */ - fun gradientNCycles(): Int { - return theGradNCyc - } - - /** - * - * gradientStepTolerance. - * - * @return a double. - */ - fun gradientStepTolerance(): Double { - return theGradTlrStp - } - - /** - * - * gradientTolerance. - * - * @return a double. - */ - fun gradientTolerance(): Double { - return theGradTlr - } - - /** - * - * hessianG2Tolerance. - * - * @return a double. - */ - fun hessianG2Tolerance(): Double { - return theHessTlrG2 - } - - /** - * - * hessianGradientNCycles. - * - * @return a int. - */ - fun hessianGradientNCycles(): Int { - return theHessGradNCyc - } - - /** - * - * hessianNCycles. - * - * @return a int. - */ - fun hessianNCycles(): Int { - return theHessNCyc - } - - /** - * - * hessianStepTolerance. - * - * @return a double. - */ - fun hessianStepTolerance(): Double { - return theHessTlrStp - } - - /** - * - * isHigh. - * - * @return a boolean. - */ - fun isHigh(): Boolean { - return theStrategy >= 2 - } - - /** - * - * isLow. - * - * @return a boolean. - */ - fun isLow(): Boolean { - return theStrategy <= 0 - } - - /** - * - * isMedium. - * - * @return a boolean. - */ - fun isMedium(): Boolean { - return theStrategy == 1 - } - - /** - * - * setGradientNCycles. - * - * @param n a int. - */ - fun setGradientNCycles(n: Int) { - theGradNCyc = n - } - - /** - * - * setGradientStepTolerance. - * - * @param stp a double. - */ - fun setGradientStepTolerance(stp: Double) { - theGradTlrStp = stp - } - - /** - * - * setGradientTolerance. - * - * @param toler a double. - */ - fun setGradientTolerance(toler: Double) { - theGradTlr = toler - } - - /** - * - * setHessianG2Tolerance. - * - * @param toler a double. - */ - fun setHessianG2Tolerance(toler: Double) { - theHessTlrG2 = toler - } - - /** - * - * setHessianGradientNCycles. - * - * @param n a int. - */ - fun setHessianGradientNCycles(n: Int) { - theHessGradNCyc = n - } - - /** - * - * setHessianNCycles. - * - * @param n a int. - */ - fun setHessianNCycles(n: Int) { - theHessNCyc = n - } - - /** - * - * setHessianStepTolerance. - * - * @param stp a double. - */ - fun setHessianStepTolerance(stp: Double) { - theHessTlrStp = stp - } - - fun setHighStrategy() { - theStrategy = 2 - setGradientNCycles(5) - setGradientStepTolerance(0.1) - setGradientTolerance(0.02) - setHessianNCycles(7) - setHessianStepTolerance(0.1) - setHessianG2Tolerance(0.02) - setHessianGradientNCycles(6) - } - - /** - * - * setLowStrategy. - */ - fun setLowStrategy() { - theStrategy = 0 - setGradientNCycles(2) - setGradientStepTolerance(0.5) - setGradientTolerance(0.1) - setHessianNCycles(3) - setHessianStepTolerance(0.5) - setHessianG2Tolerance(0.1) - setHessianGradientNCycles(1) - } - - /** - * - * setMediumStrategy. - */ - fun setMediumStrategy() { - theStrategy = 1 - setGradientNCycles(3) - setGradientStepTolerance(0.3) - setGradientTolerance(0.05) - setHessianNCycles(5) - setHessianStepTolerance(0.3) - setHessianG2Tolerance(0.05) - setHessianGradientNCycles(2) - } - - /** - * - * strategy. - * - * @return a int. - */ - fun strategy(): Int { - return theStrategy - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserCovariance.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserCovariance.kt deleted file mode 100644 index 297588f8e..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserCovariance.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * MnUserCovariance is the external covariance matrix designed for the - * interaction of the user. The result of the minimization (internal covariance - * matrix) is converted into the user representable format. It can also be used - * as input prior to the minimization. The size of the covariance matrix is - * according to the number of variable parameters (free and limited). - * - * @version $Id$ - * @author Darksnake - */ -class MnUserCovariance { - private var theData: DoubleArray - private var theNRow: Int - - private constructor(other: MnUserCovariance) { - theData = other.theData.clone() - theNRow = other.theNRow - } - - internal constructor() { - theData = DoubleArray(0) - theNRow = 0 - } - - /* - * covariance matrix is stored in upper triangular packed storage format, - * e.g. the elements in the array are arranged like - * {a(0,0), a(0,1), a(1,1), a(0,2), a(1,2), a(2,2), ...}, - * the size is nrow*(nrow+1)/2. - */ - internal constructor(data: DoubleArray, nrow: Int) { - require(data.size == nrow * (nrow + 1) / 2) { "Inconsistent arguments" } - theData = data - theNRow = nrow - } - - /** - * - * Constructor for MnUserCovariance. - * - * @param nrow a int. - */ - constructor(nrow: Int) { - theData = DoubleArray(nrow * (nrow + 1) / 2) - theNRow = nrow - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun copy(): MnUserCovariance { - return MnUserCovariance(this) - } - - fun data(): DoubleArray { - return theData - } - - /** - * - * get. - * - * @param row a int. - * @param col a int. - * @return a double. - */ - operator fun get(row: Int, col: Int): Double { - require(!(row >= theNRow || col >= theNRow)) - return if (row > col) { - theData[col + row * (row + 1) / 2] - } else { - theData[row + col * (col + 1) / 2] - } - } - - /** - * - * ncol. - * - * @return a int. - */ - fun ncol(): Int { - return theNRow - } - - /** - * - * nrow. - * - * @return a int. - */ - fun nrow(): Int { - return theNRow - } - - fun scale(f: Double) { - for (i in theData.indices) { - theData[i] *= f - } - } - - /** - * - * set. - * - * @param row a int. - * @param col a int. - * @param value a double. - */ - operator fun set(row: Int, col: Int, value: Double) { - require(!(row >= theNRow || col >= theNRow)) - if (row > col) { - theData[col + row * (row + 1) / 2] = value - } else { - theData[row + col * (col + 1) / 2] = value - } - } - - fun size(): Int { - return theData.size - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserFcn.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserFcn.kt deleted file mode 100644 index 8198a41ab..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserFcn.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * - * @version $Id$ - */ -internal class MnUserFcn(fcn: MultiFunction?, errDef: Double, trafo: MnUserTransformation) : MnFcn(fcn, errDef) { - private val theTransform: MnUserTransformation = trafo - override fun value(v: RealVector): Double { - return super.value(theTransform.transform(v)) - } - -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt deleted file mode 100644 index e80dd60a1..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt +++ /dev/null @@ -1,756 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.minuit.* - -/** - * The class MnUserParameterState contains the MnUserParameters and the - * MnUserCovariance. It can be created on input by the user, or by MINUIT itself - * as user representable format of the result of the minimization. - * - * @version $Id$ - * @author Darksnake - */ -class MnUserParameterState { - private var theCovariance: MnUserCovariance - private var theCovarianceValid = false - private var theEDM = 0.0 - private var theFVal = 0.0 - private var theGCCValid = false - private var theGlobalCC: MnGlobalCorrelationCoeff? = null - private var theIntCovariance: MnUserCovariance - private var theIntParameters: MutableList - private var theNFcn = 0 - private var theParameters: MnUserParameters - private var theValid: Boolean - - internal constructor() { - theValid = false - theCovarianceValid = false - theParameters = MnUserParameters() - theCovariance = MnUserCovariance() - theIntParameters = java.util.ArrayList() - theIntCovariance = MnUserCovariance() - } - - private constructor(other: MnUserParameterState) { - theValid = other.theValid - theCovarianceValid = other.theCovarianceValid - theGCCValid = other.theGCCValid - theFVal = other.theFVal - theEDM = other.theEDM - theNFcn = other.theNFcn - theParameters = other.theParameters.copy() - theCovariance = other.theCovariance - theGlobalCC = other.theGlobalCC - theIntParameters = java.util.ArrayList(other.theIntParameters) - theIntCovariance = other.theIntCovariance.copy() - } - - /** - * construct from user parameters (before minimization) - * @param par - * @param err - */ - internal constructor(par: DoubleArray, err: DoubleArray) { - theValid = true - theParameters = MnUserParameters(par, err) - theCovariance = MnUserCovariance() - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.size) - for (i in par.indices) { - theIntParameters.add(par[i]) - } - theIntCovariance = MnUserCovariance() - } - - internal constructor(par: MnUserParameters) { - theValid = true - theParameters = par - theCovariance = MnUserCovariance() - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.variableParameters()) - theIntCovariance = MnUserCovariance() - val i = 0 - for (ipar in par.parameters()) { - if (ipar.isConst() || ipar.isFixed()) { - continue - } - if (ipar.hasLimits()) { - theIntParameters.add(ext2int(ipar.number(), ipar.value())) - } else { - theIntParameters.add(ipar.value()) - } - } - } - - /** - * construct from user parameters + covariance (before minimization) - * @param nrow - * @param cov - */ - internal constructor(par: DoubleArray, cov: DoubleArray, nrow: Int) { - theValid = true - theCovarianceValid = true - theCovariance = MnUserCovariance(cov, nrow) - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.size) - theIntCovariance = MnUserCovariance(cov, nrow) - val err = DoubleArray(par.size) - for (i in par.indices) { - assert(theCovariance[i, i] > 0.0) - err[i] = sqrt(theCovariance[i, i]) - theIntParameters.add(par[i]) - } - theParameters = MnUserParameters(par, err) - assert(theCovariance.nrow() === variableParameters()) - } - - internal constructor(par: DoubleArray, cov: MnUserCovariance) { - theValid = true - theCovarianceValid = true - theCovariance = cov - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.size) - theIntCovariance = cov.copy() - require(!(theCovariance.nrow() !== variableParameters())) { "Bad covariance size" } - val err = DoubleArray(par.size) - for (i in par.indices) { - require(theCovariance[i, i] > 0.0) { "Bad covariance" } - err[i] = sqrt(theCovariance[i, i]) - theIntParameters.add(par[i]) - } - theParameters = MnUserParameters(par, err) - } - - internal constructor(par: MnUserParameters, cov: MnUserCovariance) { - theValid = true - theCovarianceValid = true - theParameters = par - theCovariance = cov - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList() - theIntCovariance = cov.copy() - theIntCovariance.scale(0.5) - val i = 0 - for (ipar in par.parameters()) { - if (ipar.isConst() || ipar.isFixed()) { - continue - } - if (ipar.hasLimits()) { - theIntParameters.add(ext2int(ipar.number(), ipar.value())) - } else { - theIntParameters.add(ipar.value()) - } - } - assert(theCovariance.nrow() === variableParameters()) - } - - /** - * construct from internal parameters (after minimization) - * @param trafo - * @param up - */ - internal constructor(st: MinimumState, up: Double, trafo: MnUserTransformation) { - theValid = st.isValid() - theCovarianceValid = false - theGCCValid = false - theFVal = st.fval() - theEDM = st.edm() - theNFcn = st.nfcn() - theParameters = MnUserParameters() - theCovariance = MnUserCovariance() - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList() - theIntCovariance = MnUserCovariance() - for (ipar in trafo.parameters()) { - if (ipar.isConst()) { - add(ipar.name(), ipar.value()) - } else if (ipar.isFixed()) { - add(ipar.name(), ipar.value(), ipar.error()) - if (ipar.hasLimits()) { - if (ipar.hasLowerLimit() && ipar.hasUpperLimit()) { - setLimits(ipar.name(), ipar.lowerLimit(), ipar.upperLimit()) - } else if (ipar.hasLowerLimit() && !ipar.hasUpperLimit()) { - setLowerLimit(ipar.name(), ipar.lowerLimit()) - } else { - setUpperLimit(ipar.name(), ipar.upperLimit()) - } - } - fix(ipar.name()) - } else if (ipar.hasLimits()) { - val i: Int = trafo.intOfExt(ipar.number()) - val err: Double = if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin().getEntry(i) - add(ipar.name(), - trafo.int2ext(i, st.vec().getEntry(i)), - trafo.int2extError(i, st.vec().getEntry(i), err)) - if (ipar.hasLowerLimit() && ipar.hasUpperLimit()) { - setLimits(ipar.name(), ipar.lowerLimit(), ipar.upperLimit()) - } else if (ipar.hasLowerLimit() && !ipar.hasUpperLimit()) { - setLowerLimit(ipar.name(), ipar.lowerLimit()) - } else { - setUpperLimit(ipar.name(), ipar.upperLimit()) - } - } else { - val i: Int = trafo.intOfExt(ipar.number()) - val err: Double = if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin().getEntry(i) - add(ipar.name(), st.vec().getEntry(i), err) - } - } - theCovarianceValid = st.error().isValid() - if (theCovarianceValid) { - theCovariance = trafo.int2extCovariance(st.vec(), st.error().invHessian()) - theIntCovariance = MnUserCovariance(st.error().invHessian().data().clone(), st.error().invHessian().nrow()) - theCovariance.scale(2.0 * up) - theGlobalCC = MnGlobalCorrelationCoeff(st.error().invHessian()) - theGCCValid = true - assert(theCovariance.nrow() === variableParameters()) - } - } - - /** - * add free parameter name, value, error - * - * @param err a double. - * @param val a double. - * @param name a [String] object. - */ - fun add(name: String, `val`: Double, err: Double) { - theParameters.add(name, `val`, err) - theIntParameters.add(`val`) - theCovarianceValid = false - theGCCValid = false - theValid = true - } - - /** - * add limited parameter name, value, lower bound, upper bound - * - * @param name a [String] object. - * @param val a double. - * @param low a double. - * @param err a double. - * @param up a double. - */ - fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { - theParameters.add(name, `val`, err, low, up) - theCovarianceValid = false - theIntParameters.add(ext2int(index(name), `val`)) - theGCCValid = false - theValid = true - } - - /** - * add const parameter name, value - * - * @param name a [String] object. - * @param val a double. - */ - fun add(name: String, `val`: Double) { - theParameters.add(name, `val`) - theValid = true - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun copy(): MnUserParameterState { - return MnUserParameterState(this) - } - - /** - * Covariance matrix in the external representation - * - * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun covariance(): MnUserCovariance { - return theCovariance - } - - /** - * Returns the expected vertival distance to the minimum (EDM) - * - * @return a double. - */ - fun edm(): Double { - return theEDM - } - - /** - * - * error. - * - * @param index a int. - * @return a double. - */ - fun error(index: Int): Double { - return theParameters.error(index) - } - - /** - * - * error. - * - * @param name a [String] object. - * @return a double. - */ - fun error(name: String?): Double { - return error(index(name)) - } - - /** - * - * errors. - * - * @return an array of double. - */ - fun errors(): DoubleArray { - return theParameters.errors() - } - - fun ext2int(i: Int, `val`: Double): Double { - return theParameters.trafo().ext2int(i, `val`) - } - - /** - * - * extOfInt. - * - * @param internal a int. - * @return a int. - */ - fun extOfInt(internal: Int): Int { - return theParameters.trafo().extOfInt(internal) - } - /// interaction via external number of parameter - /** - * - * fix. - * - * @param e a int. - */ - fun fix(e: Int) { - val i = intOfExt(e) - if (theCovarianceValid) { - theCovariance = MnCovarianceSqueeze.squeeze(theCovariance, i) - theIntCovariance = MnCovarianceSqueeze.squeeze(theIntCovariance, i) - } - theIntParameters.removeAt(i) - theParameters.fix(e) - theGCCValid = false - } - /// interaction via name of parameter - /** - * - * fix. - * - * @param name a [String] object. - */ - fun fix(name: String?) { - fix(index(name)) - } - - /** - * returns the function value at the minimum - * - * @return a double. - */ - fun fval(): Double { - return theFVal - } - - /** - * transformation internal <-> external - * @return - */ - fun getTransformation(): MnUserTransformation { - return theParameters.trafo() - } - - fun globalCC(): MnGlobalCorrelationCoeff? { - return theGlobalCC - } - - /** - * Returns - * true if the the state has a valid covariance, - * false otherwise. - * - * @return a boolean. - */ - fun hasCovariance(): Boolean { - return theCovarianceValid - } - - /** - * - * hasGlobalCC. - * - * @return a boolean. - */ - fun hasGlobalCC(): Boolean { - return theGCCValid - } - - /** - * convert name into external number of parameter - * - * @param name a [String] object. - * @return a int. - */ - fun index(name: String?): Int { - return theParameters.index(name) - } - - // transformation internal <-> external - fun int2ext(i: Int, `val`: Double): Double { - return theParameters.trafo().int2ext(i, `val`) - } - - fun intCovariance(): MnUserCovariance { - return theIntCovariance - } - - fun intOfExt(ext: Int): Int { - return theParameters.trafo().intOfExt(ext) - } - - /** - * Minuit internal representation - * @return - */ - fun intParameters(): List { - return theIntParameters - } - - /** - * Returns - * true if the the state is valid, - * false if not - * - * @return a boolean. - */ - fun isValid(): Boolean { - return theValid - } - - // facade: forward interface of MnUserParameters and MnUserTransformation - fun minuitParameters(): List { - return theParameters.parameters() - } - - /** - * convert external number into name of parameter - * - * @param index a int. - * @return a [String] object. - */ - fun name(index: Int): String { - return theParameters.name(index) - } - - /** - * Returns the number of function calls during the minimization. - * - * @return a int. - */ - fun nfcn(): Int { - return theNFcn - } - - fun parameter(i: Int): MinuitParameter { - return theParameters.parameter(i) - } - - //user external representation - fun parameters(): MnUserParameters { - return theParameters - } - - /** - * access to parameters and errors in column-wise representation - * - * @return an array of double. - */ - fun params(): DoubleArray { - return theParameters.params() - } - - /** - * - * precision. - * - * @return a [hep.dataforge.MINUIT.MnMachinePrecision] object. - */ - fun precision(): MnMachinePrecision { - return theParameters.precision() - } - - /** - * - * release. - * - * @param e a int. - */ - fun release(e: Int) { - theParameters.release(e) - theCovarianceValid = false - theGCCValid = false - val i = intOfExt(e) - if (parameter(e).hasLimits()) { - theIntParameters.add(i, ext2int(e, parameter(e).value())) - } else { - theIntParameters.add(i, parameter(e).value()) - } - } - - /** - * - * release. - * - * @param name a [String] object. - */ - fun release(name: String?) { - release(index(name)) - } - - /** - * - * removeLimits. - * - * @param e a int. - */ - fun removeLimits(e: Int) { - theParameters.removeLimits(e) - theCovarianceValid = false - theGCCValid = false - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - theIntParameters[intOfExt(e)] = value(e) - } - } - - /** - * - * removeLimits. - * - * @param name a [String] object. - */ - fun removeLimits(name: String?) { - removeLimits(index(name)) - } - - /** - * - * setError. - * - * @param e a int. - * @param err a double. - * @param err a double. - */ - fun setError(e: Int, err: Double) { - theParameters.setError(e, err) - } - - /** - * - * setError. - * - * @param name a [String] object. - * @param err a double. - */ - fun setError(name: String?, err: Double) { - setError(index(name), err) - } - - /** - * - * setLimits. - * - * @param e a int. - * @param low a double. - * @param up a double. - */ - fun setLimits(e: Int, low: Double, up: Double) { - theParameters.setLimits(e, low, up) - theCovarianceValid = false - theGCCValid = false - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - val i = intOfExt(e) - if (low < theIntParameters[i] && theIntParameters[i] < up) { - theIntParameters[i] = ext2int(e, theIntParameters[i]) - } else { - theIntParameters[i] = ext2int(e, 0.5 * (low + up)) - } - } - } - - /** - * - * setLimits. - * - * @param name a [String] object. - * @param low a double. - * @param up a double. - */ - fun setLimits(name: String?, low: Double, up: Double) { - setLimits(index(name), low, up) - } - - /** - * - * setLowerLimit. - * - * @param e a int. - * @param low a double. - */ - fun setLowerLimit(e: Int, low: Double) { - theParameters.setLowerLimit(e, low) - theCovarianceValid = false - theGCCValid = false - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - val i = intOfExt(e) - if (low < theIntParameters[i]) { - theIntParameters[i] = ext2int(e, theIntParameters[i]) - } else { - theIntParameters[i] = ext2int(e, low + 0.5 * abs(low + 1.0)) - } - } - } - - /** - * - * setLowerLimit. - * - * @param name a [String] object. - * @param low a double. - */ - fun setLowerLimit(name: String?, low: Double) { - setLowerLimit(index(name), low) - } - - /** - * - * setPrecision. - * - * @param eps a double. - */ - fun setPrecision(eps: Double) { - theParameters.setPrecision(eps) - } - - /** - * - * setUpperLimit. - * - * @param e a int. - * @param up a double. - */ - fun setUpperLimit(e: Int, up: Double) { - theParameters.setUpperLimit(e, up) - theCovarianceValid = false - theGCCValid = false - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - val i = intOfExt(e) - if (theIntParameters[i] < up) { - theIntParameters[i] = ext2int(e, theIntParameters[i]) - } else { - theIntParameters[i] = ext2int(e, up - 0.5 * abs(up + 1.0)) - } - } - } - - /** - * - * setUpperLimit. - * - * @param name a [String] object. - * @param up a double. - */ - fun setUpperLimit(name: String?, up: Double) { - setUpperLimit(index(name), up) - } - - /** - * - * setValue. - * - * @param e a int. - * @param val a double. - */ - fun setValue(e: Int, `val`: Double) { - theParameters.setValue(e, `val`) - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - val i = intOfExt(e) - if (parameter(e).hasLimits()) { - theIntParameters[i] = ext2int(e, `val`) - } else { - theIntParameters[i] = `val` - } - } - } - - /** - * - * setValue. - * - * @param name a [String] object. - * @param val a double. - */ - fun setValue(name: String?, `val`: Double) { - setValue(index(name), `val`) - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } - - /** - * - * value. - * - * @param index a int. - * @return a double. - */ - fun value(index: Int): Double { - return theParameters.value(index) - } - - /** - * - * value. - * - * @param name a [String] object. - * @return a double. - */ - fun value(name: String?): Double { - return value(index(name)) - } - - /** - * - * variableParameters. - * - * @return a int. - */ - fun variableParameters(): Int { - return theParameters.variableParameters() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt deleted file mode 100644 index 9bac54b25..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * API class for the user interaction with the parameters. Serves as input to - * the minimizer as well as output from it; users can interact: fix/release - * parameters, set values and errors, etc.; parameters can be accessed via their - * parameter number or via their user-specified name. - * - * @version $Id$ - * @author Darksnake - */ -class MnUserParameters { - private var theTransformation: MnUserTransformation - - /** - * Creates a new instance of MnUserParameters - */ - constructor() { - theTransformation = MnUserTransformation() - } - - /** - * - * Constructor for MnUserParameters. - * - * @param par an array of double. - * @param err an array of double. - */ - constructor(par: DoubleArray, err: DoubleArray) { - theTransformation = MnUserTransformation(par, err) - } - - private constructor(other: MnUserParameters) { - theTransformation = other.theTransformation.copy() - } - - /** - * Add free parameter name, value, error - * - * - * When adding parameters, MINUIT assigns indices to each parameter which - * will be the same as in the double[] in the - * MultiFunction.valueOf(). That means the first parameter the user - * adds gets index 0, the second index 1, and so on. When calculating the - * function value inside FCN, MINUIT will call - * MultiFunction.valueOf() with the elements at their respective - * positions. - * - * @param err a double. - * @param val a double. - * @param name a [String] object. - */ - fun add(name: String, `val`: Double, err: Double) { - theTransformation.add(name, `val`, err) - } - - /** - * Add limited parameter name, value, lower bound, upper bound - * - * @param up a double. - * @param low a double. - * @param name a [String] object. - * @param val a double. - * @param err a double. - */ - fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { - theTransformation.add(name, `val`, err, low, up) - } - - /** - * Add const parameter name, value - * - * @param name a [String] object. - * @param val a double. - */ - fun add(name: String, `val`: Double) { - theTransformation.add(name, `val`) - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - fun copy(): MnUserParameters { - return MnUserParameters(this) - } - - /** - * - * error. - * - * @param index a int. - * @return a double. - */ - fun error(index: Int): Double { - return theTransformation.error(index) - } - - /** - * - * error. - * - * @param name a [String] object. - * @return a double. - */ - fun error(name: String?): Double { - return theTransformation.error(name) - } - - fun errors(): DoubleArray { - return theTransformation.errors() - } - /// interaction via external number of parameter - /** - * Fixes the specified parameter (so that the minimizer will no longer vary - * it) - * - * @param index a int. - */ - fun fix(index: Int) { - theTransformation.fix(index) - } - /// interaction via name of parameter - /** - * Fixes the specified parameter (so that the minimizer will no longer vary - * it) - * - * @param name a [String] object. - */ - fun fix(name: String?) { - theTransformation.fix(name) - } - - /** - * convert name into external number of parameter - * @param name - * @return - */ - fun index(name: String?): Int { - return theTransformation.index(name) - } - - /** - * convert external number into name of parameter - * @param index - * @return - */ - fun name(index: Int): String { - return theTransformation.name(index) - } - - /** - * access to single parameter - * @param index - * @return - */ - fun parameter(index: Int): MinuitParameter { - return theTransformation.parameter(index) - } - - /** - * access to parameters (row-wise) - * @return - */ - fun parameters(): List { - return theTransformation.parameters() - } - - /** - * access to parameters and errors in column-wise representation - * @return - */ - fun params(): DoubleArray { - return theTransformation.params() - } - - /** - * - * precision. - * - * @return a [hep.dataforge.MINUIT.MnMachinePrecision] object. - */ - fun precision(): MnMachinePrecision { - return theTransformation.precision() - } - - /** - * Releases the specified parameter (so that the minimizer can vary it) - * - * @param index a int. - */ - fun release(index: Int) { - theTransformation.release(index) - } - - /** - * Releases the specified parameter (so that the minimizer can vary it) - * - * @param name a [String] object. - */ - fun release(name: String?) { - theTransformation.release(name) - } - - /** - * - * removeLimits. - * - * @param index a int. - */ - fun removeLimits(index: Int) { - theTransformation.removeLimits(index) - } - - /** - * - * removeLimits. - * - * @param name a [String] object. - */ - fun removeLimits(name: String?) { - theTransformation.removeLimits(name) - } - - /** - * - * setError. - * - * @param index a int. - * @param err a double. - */ - fun setError(index: Int, err: Double) { - theTransformation.setError(index, err) - } - - /** - * - * setError. - * - * @param name a [String] object. - * @param err a double. - */ - fun setError(name: String?, err: Double) { - theTransformation.setError(name, err) - } - - /** - * Set the lower and upper bound on the specified variable. - * - * @param up a double. - * @param low a double. - * @param index a int. - */ - fun setLimits(index: Int, low: Double, up: Double) { - theTransformation.setLimits(index, low, up) - } - - /** - * Set the lower and upper bound on the specified variable. - * - * @param up a double. - * @param low a double. - * @param name a [String] object. - */ - fun setLimits(name: String?, low: Double, up: Double) { - theTransformation.setLimits(name, low, up) - } - - /** - * - * setLowerLimit. - * - * @param index a int. - * @param low a double. - */ - fun setLowerLimit(index: Int, low: Double) { - theTransformation.setLowerLimit(index, low) - } - - /** - * - * setLowerLimit. - * - * @param name a [String] object. - * @param low a double. - */ - fun setLowerLimit(name: String?, low: Double) { - theTransformation.setLowerLimit(name, low) - } - - /** - * - * setPrecision. - * - * @param eps a double. - */ - fun setPrecision(eps: Double) { - theTransformation.setPrecision(eps) - } - - /** - * - * setUpperLimit. - * - * @param index a int. - * @param up a double. - */ - fun setUpperLimit(index: Int, up: Double) { - theTransformation.setUpperLimit(index, up) - } - - /** - * - * setUpperLimit. - * - * @param name a [String] object. - * @param up a double. - */ - fun setUpperLimit(name: String?, up: Double) { - theTransformation.setUpperLimit(name, up) - } - - /** - * Set the value of parameter. The parameter in question may be variable, - * fixed, or constant, but must be defined. - * - * @param index a int. - * @param val a double. - */ - fun setValue(index: Int, `val`: Double) { - theTransformation.setValue(index, `val`) - } - - /** - * Set the value of parameter. The parameter in question may be variable, - * fixed, or constant, but must be defined. - * - * @param name a [String] object. - * @param val a double. - */ - fun setValue(name: String?, `val`: Double) { - theTransformation.setValue(name, `val`) - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } - - fun trafo(): MnUserTransformation { - return theTransformation - } - - /** - * - * value. - * - * @param index a int. - * @return a double. - */ - fun value(index: Int): Double { - return theTransformation.value(index) - } - - /** - * - * value. - * - * @param name a [String] object. - * @return a double. - */ - fun value(name: String?): Double { - return theTransformation.value(name) - } - - /** - * - * variableParameters. - * - * @return a int. - */ - fun variableParameters(): Int { - return theTransformation.variableParameters() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt deleted file mode 100644 index 1066ac2da..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * knows how to andThen between user specified parameters (external) and - * internal parameters used for minimization - * - * Жуткий октопус, который занимается преобразованием внешних параметров во внутренние - * TODO по возможности отказаться от использования этого монстра - * @version $Id$ - */ -class MnUserTransformation { - private val nameMap: MutableMap = HashMap() - private var theCache: MutableList - private var theExtOfInt: MutableList - private var theParameters: MutableList - private var thePrecision: MnMachinePrecision - - constructor() { - thePrecision = MnMachinePrecision() - theParameters = java.util.ArrayList() - theExtOfInt = java.util.ArrayList() - theCache = java.util.ArrayList(0) - } - - private constructor(other: MnUserTransformation) { - thePrecision = other.thePrecision - theParameters = java.util.ArrayList(other.theParameters.size) - for (par in other.theParameters) { - theParameters.add(par.copy()) - } - theExtOfInt = java.util.ArrayList(other.theExtOfInt) - theCache = java.util.ArrayList(other.theCache) - } - - constructor(par: DoubleArray, err: DoubleArray) { - thePrecision = MnMachinePrecision() - theParameters = java.util.ArrayList(par.size) - theExtOfInt = java.util.ArrayList(par.size) - theCache = java.util.ArrayList(par.size) - for (i in par.indices) { - add("p$i", par[i], err[i]) - } - } - - /** - * add free parameter - * @param err - * @param val - */ - fun add(name: String, `val`: Double, err: Double) { - require(!nameMap.containsKey(name)) { "duplicate name: $name" } - nameMap[name] = theParameters.size - theExtOfInt.add(theParameters.size) - theCache.add(`val`) - theParameters.add(MinuitParameter(theParameters.size, name, `val`, err)) - } - - /** - * add limited parameter - * @param up - * @param low - */ - fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { - require(!nameMap.containsKey(name)) { "duplicate name: $name" } - nameMap[name] = theParameters.size - theExtOfInt.add(theParameters.size) - theCache.add(`val`) - theParameters.add(MinuitParameter(theParameters.size, name, `val`, err, low, up)) - } - - /** - * add parameter - * @param name - * @param val - */ - fun add(name: String, `val`: Double) { - require(!nameMap.containsKey(name)) { "duplicate name: $name" } - nameMap[name] = theParameters.size - theCache.add(`val`) - theParameters.add(MinuitParameter(theParameters.size, name, `val`)) - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnUserTransformation] object. - */ - fun copy(): MnUserTransformation { - return MnUserTransformation(this) - } - - fun dInt2Ext(i: Int, `val`: Double): Double { - var dd = 1.0 - val parm: MinuitParameter = theParameters[theExtOfInt[i]] - if (parm.hasLimits()) { - dd = if (parm.hasUpperLimit() && parm.hasLowerLimit()) { - theDoubleLimTrafo.dInt2Ext(`val`, - parm.upperLimit(), - parm.lowerLimit()) - } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) { - theUpperLimTrafo.dInt2Ext(`val`, parm.upperLimit()) - } else { - theLowerLimTrafo.dInt2Ext(`val`, parm.lowerLimit()) - } - } - return dd - } - - fun error(index: Int): Double { - return theParameters[index].error() - } - - fun error(name: String?): Double { - return error(index(name)) - } - - fun errors(): DoubleArray { - val result = DoubleArray(theParameters.size) - var i = 0 - for (parameter in theParameters) { - result[i++] = parameter.error() - } - return result - } - - fun ext2int(i: Int, `val`: Double): Double { - val parm: MinuitParameter = theParameters[i] - return if (parm.hasLimits()) { - if (parm.hasUpperLimit() && parm.hasLowerLimit()) { - theDoubleLimTrafo.ext2int(`val`, - parm.upperLimit(), - parm.lowerLimit(), - precision()) - } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) { - theUpperLimTrafo.ext2int(`val`, - parm.upperLimit(), - precision()) - } else { - theLowerLimTrafo.ext2int(`val`, - parm.lowerLimit(), - precision()) - } - } else `val` - } - - fun extOfInt(internal: Int): Int { - return theExtOfInt[internal] - } - - /** - * interaction via external number of parameter - * @param index - */ - fun fix(index: Int) { - val iind = intOfExt(index) - theExtOfInt.removeAt(iind) - theParameters[index].fix() - } - - /** - * interaction via name of parameter - * @param name - */ - fun fix(name: String?) { - fix(index(name)) - } - - /** - * convert name into external number of parameter - * @param name - * @return - */ - fun index(name: String?): Int { - return nameMap[name]!! - } - - fun int2ext(i: Int, `val`: Double): Double { - val parm: MinuitParameter = theParameters[theExtOfInt[i]] - return if (parm.hasLimits()) { - if (parm.hasUpperLimit() && parm.hasLowerLimit()) { - theDoubleLimTrafo.int2ext(`val`, - parm.upperLimit(), - parm.lowerLimit()) - } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) { - theUpperLimTrafo.int2ext(`val`, parm.upperLimit()) - } else { - theLowerLimTrafo.int2ext(`val`, parm.lowerLimit()) - } - } else `val` - } - - fun int2extCovariance(vec: RealVector, cov: MnAlgebraicSymMatrix): MnUserCovariance { - val result = MnUserCovariance(cov.nrow()) - for (i in 0 until vec.getDimension()) { - var dxdi = 1.0 - if (theParameters[theExtOfInt[i]].hasLimits()) { - dxdi = dInt2Ext(i, vec.getEntry(i)) - } - for (j in i until vec.getDimension()) { - var dxdj = 1.0 - if (theParameters[theExtOfInt[j]].hasLimits()) { - dxdj = dInt2Ext(j, vec.getEntry(j)) - } - result[i, j] = dxdi * cov[i, j] * dxdj - } - } - return result - } - - fun int2extError(i: Int, `val`: Double, err: Double): Double { - var dx = err - val parm: MinuitParameter = theParameters[theExtOfInt[i]] - if (parm.hasLimits()) { - val ui = int2ext(i, `val`) - var du1 = int2ext(i, `val` + dx) - ui - val du2 = int2ext(i, `val` - dx) - ui - if (parm.hasUpperLimit() && parm.hasLowerLimit()) { - if (dx > 1.0) { - du1 = parm.upperLimit() - parm.lowerLimit() - } - dx = 0.5 * (abs(du1) + abs(du2)) - } else { - dx = 0.5 * (abs(du1) + abs(du2)) - } - } - return dx - } - - fun intOfExt(ext: Int): Int { - for (iind in theExtOfInt.indices) { - if (ext == theExtOfInt[iind]) { - return iind - } - } - throw IllegalArgumentException("ext=$ext") - } - - /** - * convert external number into name of parameter - * @param index - * @return - */ - fun name(index: Int): String { - return theParameters[index].name() - } - - /** - * access to single parameter - * @param index - * @return - */ - fun parameter(index: Int): MinuitParameter { - return theParameters[index] - } - - fun parameters(): List { - return theParameters - } - - //access to parameters and errors in column-wise representation - fun params(): DoubleArray { - val result = DoubleArray(theParameters.size) - var i = 0 - for (parameter in theParameters) { - result[i++] = parameter.value() - } - return result - } - - fun precision(): MnMachinePrecision { - return thePrecision - } - - fun release(index: Int) { - require(!theExtOfInt.contains(index)) { "index=$index" } - theExtOfInt.add(index) - Collections.sort(theExtOfInt) - theParameters[index].release() - } - - fun release(name: String?) { - release(index(name)) - } - - fun removeLimits(index: Int) { - theParameters[index].removeLimits() - } - - fun removeLimits(name: String?) { - removeLimits(index(name)) - } - - fun setError(index: Int, err: Double) { - theParameters[index].setError(err) - } - - fun setError(name: String?, err: Double) { - setError(index(name), err) - } - - fun setLimits(index: Int, low: Double, up: Double) { - theParameters[index].setLimits(low, up) - } - - fun setLimits(name: String?, low: Double, up: Double) { - setLimits(index(name), low, up) - } - - fun setLowerLimit(index: Int, low: Double) { - theParameters[index].setLowerLimit(low) - } - - fun setLowerLimit(name: String?, low: Double) { - setLowerLimit(index(name), low) - } - - fun setPrecision(eps: Double) { - thePrecision.setPrecision(eps) - } - - fun setUpperLimit(index: Int, up: Double) { - theParameters[index].setUpperLimit(up) - } - - fun setUpperLimit(name: String?, up: Double) { - setUpperLimit(index(name), up) - } - - fun setValue(index: Int, `val`: Double) { - theParameters[index].setValue(`val`) - theCache[index] = `val` - } - - fun setValue(name: String?, `val`: Double) { - setValue(index(name), `val`) - } - - fun transform(pstates: RealVector): ArrayRealVector { - // FixMe: Worry about efficiency here - val result = ArrayRealVector(theCache.size) - for (i in 0 until result.getDimension()) { - result.setEntry(i, theCache[i]) - } - for (i in 0 until pstates.getDimension()) { - if (theParameters[theExtOfInt[i]].hasLimits()) { - result.setEntry(theExtOfInt[i], int2ext(i, pstates.getEntry(i))) - } else { - result.setEntry(theExtOfInt[i], pstates.getEntry(i)) - } - } - return result - } - - //forwarded interface - fun value(index: Int): Double { - return theParameters[index].value() - } - - fun value(name: String?): Double { - return value(index(name)) - } - - fun variableParameters(): Int { - return theExtOfInt.size - } - - companion object { - private val theDoubleLimTrafo: SinParameterTransformation = SinParameterTransformation() - private val theLowerLimTrafo: SqrtLowParameterTransformation = SqrtLowParameterTransformation() - private val theUpperLimTrafo: SqrtUpParameterTransformation = SqrtUpParameterTransformation() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUtils.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUtils.kt deleted file mode 100644 index d9f3e1bd5..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUtils.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * Utilities for operating on vectors and matrices - * - * @version $Id$ - */ -internal object MnUtils { - fun absoluteSumOfElements(m: MnAlgebraicSymMatrix): Double { - val data: DoubleArray = m.data() - var result = 0.0 - for (i in data.indices) { - result += abs(data[i]) - } - return result - } - - fun add(v1: RealVector, v2: RealVector?): RealVector { - return v1.add(v2) - } - - fun add(m1: MnAlgebraicSymMatrix, m2: MnAlgebraicSymMatrix): MnAlgebraicSymMatrix { - require(!(m1.size() !== m2.size())) { "Incompatible matrices" } - val result: MnAlgebraicSymMatrix = m1.copy() - val a: DoubleArray = result.data() - val b: DoubleArray = m2.data() - for (i in a.indices) { - a[i] += b[i] - } - return result - } - - fun div(m: MnAlgebraicSymMatrix?, scale: Double): MnAlgebraicSymMatrix { - return mul(m, 1 / scale) - } - - fun div(m: RealVector?, scale: Double): RealVector { - return mul(m, 1 / scale) - } - - fun innerProduct(v1: RealVector, v2: RealVector): Double { - require(!(v1.getDimension() !== v2.getDimension())) { "Incompatible vectors" } - var total = 0.0 - for (i in 0 until v1.getDimension()) { - total += v1.getEntry(i) * v2.getEntry(i) - } - return total - } - - fun mul(v1: RealVector, scale: Double): RealVector { - return v1.mapMultiply(scale) - } - - fun mul(m1: MnAlgebraicSymMatrix, scale: Double): MnAlgebraicSymMatrix { - val result: MnAlgebraicSymMatrix = m1.copy() - val a: DoubleArray = result.data() - for (i in a.indices) { - a[i] *= scale - } - return result - } - - fun mul(m1: MnAlgebraicSymMatrix, v1: RealVector): ArrayRealVector { - require(!(m1.nrow() !== v1.getDimension())) { "Incompatible arguments" } - val result = ArrayRealVector(m1.nrow()) - for (i in 0 until result.getDimension()) { - var total = 0.0 - for (k in 0 until result.getDimension()) { - total += m1[i, k] * v1.getEntry(k) - } - result.setEntry(i, total) - } - return result - } - - fun mul(m1: MnAlgebraicSymMatrix, m2: MnAlgebraicSymMatrix): MnAlgebraicSymMatrix { - require(!(m1.size() !== m2.size())) { "Incompatible matrices" } - val n: Int = m1.nrow() - val result = MnAlgebraicSymMatrix(n) - for (i in 0 until n) { - for (j in 0..i) { - var total = 0.0 - for (k in 0 until n) { - total += m1[i, k] * m2[k, j] - } - result[i, j] = total - } - } - return result - } - - fun outerProduct(v2: RealVector): MnAlgebraicSymMatrix { - // Fixme: check this. I am assuming this is just an outer-product of vector - // with itself. - val n: Int = v2.getDimension() - val result = MnAlgebraicSymMatrix(n) - val data: DoubleArray = v2.toArray() - for (i in 0 until n) { - for (j in 0..i) { - result[i, j] = data[i] * data[j] - } - } - return result - } - - fun similarity(avec: RealVector, mat: MnAlgebraicSymMatrix): Double { - val n: Int = avec.getDimension() - val tmp: RealVector = mul(mat, avec) - var result = 0.0 - for (i in 0 until n) { - result += tmp.getEntry(i) * avec.getEntry(i) - } - return result - } - - fun sub(v1: RealVector, v2: RealVector?): RealVector { - return v1.subtract(v2) - } - - fun sub(m1: MnAlgebraicSymMatrix, m2: MnAlgebraicSymMatrix): MnAlgebraicSymMatrix { - require(!(m1.size() !== m2.size())) { "Incompatible matrices" } - val result: MnAlgebraicSymMatrix = m1.copy() - val a: DoubleArray = result.data() - val b: DoubleArray = m2.data() - for (i in a.indices) { - a[i] -= b[i] - } - return result - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt deleted file mode 100644 index 84130d24f..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -abstract class ModularFunctionMinimizer { - abstract fun builder(): MinimumBuilder - fun minimize( - fcn: MultiFunction?, - st: MnUserParameterState, - strategy: MnStrategy, - maxfcn: Int, - toler: Double, - errorDef: Double, - useAnalyticalGradient: Boolean, - checkGradient: Boolean - ): FunctionMinimum { - var maxfcn = maxfcn - val mfcn = MnUserFcn(fcn, errorDef, st.getTransformation()) - val gc: GradientCalculator - var providesAllDerivs = true - /* - * Проверяем в явном виде, что все аналитические производные присутствуют - * TODO сделать возможность того, что часть производных задается аналитически, а часть численно - */for (i in 0 until fcn.getDimension()) { - if (!fcn.providesDeriv(i)) providesAllDerivs = false - } - gc = if (providesAllDerivs && useAnalyticalGradient) { - AnalyticalGradientCalculator(fcn, st.getTransformation(), checkGradient) - } else { - Numerical2PGradientCalculator(mfcn, st.getTransformation(), strategy) - } - val npar: Int = st.variableParameters() - if (maxfcn == 0) { - maxfcn = 200 + 100 * npar + 5 * npar * npar - } - val mnseeds: MinimumSeed = seedGenerator().generate(mfcn, gc, st, strategy) - return minimize(mfcn, gc, mnseeds, strategy, maxfcn, toler) - } - - fun minimize( - mfcn: MnFcn, - gc: GradientCalculator?, - seed: MinimumSeed?, - strategy: MnStrategy?, - maxfcn: Int, - toler: Double - ): FunctionMinimum { - return builder().minimum(mfcn, gc, seed, strategy, maxfcn, toler * mfcn.errorDef()) - } - - abstract fun seedGenerator(): MinimumSeedGenerator -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt b/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt deleted file mode 100644 index 2e9ce5813..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* - -/** - * In case that one of the components of the second derivative g2 calculated by - * the numerical gradient calculator is negative, a 1dim line search in the - * direction of that component is done in order to find a better position where - * g2 is again positive. - * - * @version $Id$ - */ -internal object NegativeG2LineSearch { - fun hasNegativeG2(grad: FunctionGradient, prec: MnMachinePrecision): Boolean { - for (i in 0 until grad.getGradient().getDimension()) { - if (grad.getGradientDerivative().getEntry(i) < prec.eps2()) { - return true - } - } - return false - } - - fun search(fcn: MnFcn, st: MinimumState, gc: GradientCalculator, prec: MnMachinePrecision): MinimumState { - val negG2 = hasNegativeG2(st.gradient(), prec) - if (!negG2) { - return st - } - val n: Int = st.parameters().vec().getDimension() - var dgrad: FunctionGradient = st.gradient() - var pa: MinimumParameters = st.parameters() - var iterate = false - var iter = 0 - do { - iterate = false - for (i in 0 until n) { - if (dgrad.getGradientDerivative().getEntry(i) < prec.eps2()) { - // do line search if second derivative negative - var step: RealVector = ArrayRealVector(n) - step.setEntry(i, dgrad.getStep().getEntry(i) * dgrad.getGradient().getEntry(i)) - if (abs(dgrad.getGradient().getEntry(i)) > prec.eps2()) { - step.setEntry(i, - step.getEntry(i) * (-1.0 / abs(dgrad.getGradient().getEntry(i)))) - } - val gdel: Double = step.getEntry(i) * dgrad.getGradient().getEntry(i) - val pp: MnParabolaPoint = MnLineSearch.search(fcn, pa, step, gdel, prec) - step = MnUtils.mul(step, pp.x()) - pa = MinimumParameters(MnUtils.add(pa.vec(), step), pp.y()) - dgrad = gc.gradient(pa, dgrad) - iterate = true - break - } - } - } while (iter++ < 2 * n && iterate) - val mat = MnAlgebraicSymMatrix(n) - for (i in 0 until n) { - mat[i, i] = if (abs(dgrad.getGradientDerivative() - .getEntry(i)) > prec.eps2() - ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0 - } - val err = MinimumError(mat, 1.0) - val edm: Double = VariableMetricEDMEstimator().estimate(dgrad, err) - return MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt deleted file mode 100644 index efa1d57af..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -internal class Numerical2PGradientCalculator(fcn: MnFcn, par: MnUserTransformation, stra: MnStrategy) : - GradientCalculator { - private val theFcn: MnFcn = fcn - private val theStrategy: MnStrategy - private val theTransformation: MnUserTransformation - fun fcn(): MnFcn { - return theFcn - } - - fun gradTolerance(): Double { - return strategy().gradientTolerance() - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters): FunctionGradient { - val gc = InitialGradientCalculator(theFcn, theTransformation, theStrategy) - val gra: FunctionGradient = gc.gradient(par) - return gradient(par, gra) - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters, gradient: FunctionGradient): FunctionGradient { - require(par.isValid()) { "Parameters are invalid" } - val x: RealVector = par.vec().copy() - val fcnmin: Double = par.fval() - val dfmin: Double = 8.0 * precision().eps2() * (abs(fcnmin) + theFcn.errorDef()) - val vrysml: Double = 8.0 * precision().eps() * precision().eps() - val n: Int = x.getDimension() - val grd: RealVector = gradient.getGradient().copy() - val g2: RealVector = gradient.getGradientDerivative().copy() - val gstep: RealVector = gradient.getStep().copy() - for (i in 0 until n) { - val xtf: Double = x.getEntry(i) - val epspri: Double = precision().eps2() + abs(grd.getEntry(i) * precision().eps2()) - var stepb4 = 0.0 - for (j in 0 until ncycle()) { - val optstp: Double = sqrt(dfmin / (abs(g2.getEntry(i)) + epspri)) - var step: Double = max(optstp, abs(0.1 * gstep.getEntry(i))) - if (trafo().parameter(trafo().extOfInt(i)).hasLimits()) { - if (step > 0.5) { - step = 0.5 - } - } - val stpmax: Double = 10.0 * abs(gstep.getEntry(i)) - if (step > stpmax) { - step = stpmax - } - val stpmin: Double = - max(vrysml, 8.0 * abs(precision().eps2() * x.getEntry(i))) - if (step < stpmin) { - step = stpmin - } - if (abs((step - stepb4) / step) < stepTolerance()) { - break - } - gstep.setEntry(i, step) - stepb4 = step - x.setEntry(i, xtf + step) - val fs1: Double = theFcn.value(x) - x.setEntry(i, xtf - step) - val fs2: Double = theFcn.value(x) - x.setEntry(i, xtf) - val grdb4: Double = grd.getEntry(i) - grd.setEntry(i, 0.5 * (fs1 - fs2) / step) - g2.setEntry(i, (fs1 + fs2 - 2.0 * fcnmin) / step / step) - if (abs(grdb4 - grd.getEntry(i)) / (abs(grd.getEntry(i)) + dfmin / step) < gradTolerance()) { - break - } - } - } - return FunctionGradient(grd, g2, gstep) - } - - fun ncycle(): Int { - return strategy().gradientNCycles() - } - - fun precision(): MnMachinePrecision { - return theTransformation.precision() - } - - fun stepTolerance(): Double { - return strategy().gradientStepTolerance() - } - - fun strategy(): MnStrategy { - return theStrategy - } - - fun trafo(): MnUserTransformation { - return theTransformation - } - - init { - theTransformation = par - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt deleted file mode 100644 index 57f910a26..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * Performs a minimization using the simplex method of Nelder and Mead (ref. - * Comp. J. 7, 308 (1965)). - * - * @version $Id$ - */ -internal class ScanBuilder : MinimumBuilder { - /** {@inheritDoc} */ - fun minimum( - mfcn: MnFcn, - gc: GradientCalculator?, - seed: MinimumSeed, - stra: MnStrategy?, - maxfcn: Int, - toler: Double - ): FunctionMinimum { - val x: RealVector = seed.parameters().vec().copy() - val upst = MnUserParameterState(seed.state(), mfcn.errorDef(), seed.trafo()) - val scan = MnParameterScan(mfcn.fcn(), upst.parameters(), seed.fval()) - var amin: Double = scan.fval() - val n: Int = seed.trafo().variableParameters() - val dirin: RealVector = ArrayRealVector(n) - for (i in 0 until n) { - val ext: Int = seed.trafo().extOfInt(i) - scan.scan(ext) - if (scan.fval() < amin) { - amin = scan.fval() - x.setEntry(i, seed.trafo().ext2int(ext, scan.parameters().value(ext))) - } - dirin.setEntry(i, sqrt(2.0 * mfcn.errorDef() * seed.error().invHessian()[i, i])) - } - val mp = MinimumParameters(x, dirin, amin) - val st = MinimumState(mp, 0.0, mfcn.numOfCalls()) - val states: MutableList = java.util.ArrayList(1) - states.add(st) - return FunctionMinimum(seed, states, mfcn.errorDef()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ScanMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/ScanMinimizer.kt deleted file mode 100644 index e39a49c0d..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/ScanMinimizer.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class ScanMinimizer : ModularFunctionMinimizer() { - private val theBuilder: ScanBuilder - private val theSeedGenerator: SimplexSeedGenerator = SimplexSeedGenerator() - override fun builder(): MinimumBuilder { - return theBuilder - } - - override fun seedGenerator(): MinimumSeedGenerator { - return theSeedGenerator - } - - init { - theBuilder = ScanBuilder() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt deleted file mode 100644 index 0b10155ff..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class SimplexBuilder : MinimumBuilder { - /** {@inheritDoc} */ - fun minimum( - mfcn: MnFcn, - gc: GradientCalculator?, - seed: MinimumSeed, - strategy: MnStrategy?, - maxfcn: Int, - minedm: Double - ): FunctionMinimum { - val prec: MnMachinePrecision = seed.precision() - val x: RealVector = seed.parameters().vec().copy() - val step: RealVector = MnUtils.mul(seed.gradient().getStep(), 10.0) - val n: Int = x.getDimension() - val wg = 1.0 / n - val alpha = 1.0 - val beta = 0.5 - val gamma = 2.0 - val rhomin = 4.0 - val rhomax = 8.0 - val rho1 = 1.0 + alpha - val rho2 = 1.0 + alpha * gamma - val simpl: MutableList> = java.util.ArrayList>(n + 1) - simpl.add(Pair(seed.fval(), x.copy())) - var jl = 0 - var jh = 0 - var amin: Double = seed.fval() - var aming: Double = seed.fval() - for (i in 0 until n) { - val dmin: Double = 8.0 * prec.eps2() * (abs(x.getEntry(i)) + prec.eps2()) - if (step.getEntry(i) < dmin) { - step.setEntry(i, dmin) - } - x.setEntry(i, x.getEntry(i) + step.getEntry(i)) - val tmp: Double = mfcn.value(x) - if (tmp < amin) { - amin = tmp - jl = i + 1 - } - if (tmp > aming) { - aming = tmp - jh = i + 1 - } - simpl.add(Pair(tmp, x.copy())) - x.setEntry(i, x.getEntry(i) - step.getEntry(i)) - } - val simplex = SimplexParameters(simpl, jh, jl) - do { - amin = simplex[jl].getFirst() - jl = simplex.jl() - jh = simplex.jh() - var pbar: RealVector = ArrayRealVector(n) - for (i in 0 until n + 1) { - if (i == jh) { - continue - } - pbar = MnUtils.add(pbar, MnUtils.mul(simplex[i].getSecond(), wg)) - } - val pstar: RealVector = - MnUtils.sub(MnUtils.mul(pbar, 1.0 + alpha), MnUtils.mul(simplex[jh].getSecond(), alpha)) - val ystar: Double = mfcn.value(pstar) - if (ystar > amin) { - if (ystar < simplex[jh].getFirst()) { - simplex.update(ystar, pstar) - if (jh != simplex.jh()) { - continue - } - } - val pstst: RealVector = - MnUtils.add(MnUtils.mul(simplex[jh].getSecond(), beta), MnUtils.mul(pbar, 1.0 - beta)) - val ystst: Double = mfcn.value(pstst) - if (ystst > simplex[jh].getFirst()) { - break - } - simplex.update(ystst, pstst) - continue - } - var pstst: RealVector = MnUtils.add(MnUtils.mul(pstar, gamma), MnUtils.mul(pbar, 1.0 - gamma)) - var ystst: Double = mfcn.value(pstst) - val y1: Double = (ystar - simplex[jh].getFirst()) * rho2 - val y2: Double = (ystst - simplex[jh].getFirst()) * rho1 - var rho = 0.5 * (rho2 * y1 - rho1 * y2) / (y1 - y2) - if (rho < rhomin) { - if (ystst < simplex[jl].getFirst()) { - simplex.update(ystst, pstst) - } else { - simplex.update(ystar, pstar) - } - continue - } - if (rho > rhomax) { - rho = rhomax - } - val prho: RealVector = - MnUtils.add(MnUtils.mul(pbar, rho), MnUtils.mul(simplex[jh].getSecond(), 1.0 - rho)) - val yrho: Double = mfcn.value(prho) - if (yrho < simplex[jl].getFirst() && yrho < ystst) { - simplex.update(yrho, prho) - continue - } - if (ystst < simplex[jl].getFirst()) { - simplex.update(ystst, pstst) - continue - } - if (yrho > simplex[jl].getFirst()) { - if (ystst < simplex[jl].getFirst()) { - simplex.update(ystst, pstst) - } else { - simplex.update(ystar, pstar) - } - continue - } - if (ystar > simplex[jh].getFirst()) { - pstst = MnUtils.add(MnUtils.mul(simplex[jh].getSecond(), beta), MnUtils.mul(pbar, 1 - beta)) - ystst = mfcn.value(pstst) - if (ystst > simplex[jh].getFirst()) { - break - } - simplex.update(ystst, pstst) - } - } while (simplex.edm() > minedm && mfcn.numOfCalls() < maxfcn) - amin = simplex[jl].getFirst() - jl = simplex.jl() - jh = simplex.jh() - var pbar: RealVector = ArrayRealVector(n) - for (i in 0 until n + 1) { - if (i == jh) { - continue - } - pbar = MnUtils.add(pbar, MnUtils.mul(simplex[i].getSecond(), wg)) - } - var ybar: Double = mfcn.value(pbar) - if (ybar < amin) { - simplex.update(ybar, pbar) - } else { - pbar = simplex[jl].getSecond() - ybar = simplex[jl].getFirst() - } - var dirin: RealVector = simplex.dirin() - // scale to sigmas on parameters werr^2 = dirin^2 * (up/edm) - dirin = MnUtils.mul(dirin, sqrt(mfcn.errorDef() / simplex.edm())) - val st = MinimumState(MinimumParameters(pbar, dirin, ybar), simplex.edm(), mfcn.numOfCalls()) - val states: MutableList = java.util.ArrayList(1) - states.add(st) - if (mfcn.numOfCalls() > maxfcn) { - MINUITPlugin.logStatic("Simplex did not converge, #fcn calls exhausted.") - return FunctionMinimum(seed, states, mfcn.errorDef(), MnReachedCallLimit()) - } - if (simplex.edm() > minedm) { - MINUITPlugin.logStatic("Simplex did not converge, edm > minedm.") - return FunctionMinimum(seed, states, mfcn.errorDef(), MnAboveMaxEdm()) - } - return FunctionMinimum(seed, states, mfcn.errorDef()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexMinimizer.kt deleted file mode 100644 index f4bbcc320..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexMinimizer.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class SimplexMinimizer : ModularFunctionMinimizer() { - private val theBuilder: SimplexBuilder - private val theSeedGenerator: SimplexSeedGenerator = SimplexSeedGenerator() - - /** {@inheritDoc} */ - override fun builder(): MinimumBuilder { - return theBuilder - } - - /** {@inheritDoc} */ - override fun seedGenerator(): MinimumSeedGenerator { - return theSeedGenerator - } - - /** - * - * Constructor for SimplexMinimizer. - */ - init { - theBuilder = SimplexBuilder() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexParameters.kt deleted file mode 100644 index fef6e2010..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexParameters.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * - * @version $Id$ - */ -internal class SimplexParameters(simpl: MutableList>, jh: Int, jl: Int) { - private var theJHigh: Int - private var theJLow: Int - private val theSimplexParameters: MutableList> - fun dirin(): ArrayRealVector { - val dirin = ArrayRealVector(theSimplexParameters.size - 1) - for (i in 0 until theSimplexParameters.size - 1) { - var pbig: Double = theSimplexParameters[0].getSecond().getEntry(i) - var plit = pbig - for (theSimplexParameter in theSimplexParameters) { - if (theSimplexParameter.getSecond().getEntry(i) < plit) { - plit = theSimplexParameter.getSecond().getEntry(i) - } - if (theSimplexParameter.getSecond().getEntry(i) > pbig) { - pbig = theSimplexParameter.getSecond().getEntry(i) - } - } - dirin.setEntry(i, pbig - plit) - } - return dirin - } - - fun edm(): Double { - return theSimplexParameters[jh()].getFirst() - theSimplexParameters[jl()].getFirst() - } - - operator fun get(i: Int): Pair { - return theSimplexParameters[i] - } - - fun jh(): Int { - return theJHigh - } - - fun jl(): Int { - return theJLow - } - - fun simplex(): List> { - return theSimplexParameters - } - - fun update(y: Double, p: RealVector?) { - theSimplexParameters.set(jh(), Pair(y, p)) - if (y < theSimplexParameters[jl()].getFirst()) { - theJLow = jh() - } - var jh = 0 - for (i in 1 until theSimplexParameters.size) { - if (theSimplexParameters[i].getFirst() > theSimplexParameters[jh].getFirst()) { - jh = i - } - } - theJHigh = jh - } - - init { - theSimplexParameters = simpl - theJHigh = jh - theJLow = jl - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt deleted file mode 100644 index 577545fc3..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class SimplexSeedGenerator : MinimumSeedGenerator { - /** {@inheritDoc} */ - fun generate(fcn: MnFcn, gc: GradientCalculator?, st: MnUserParameterState, stra: MnStrategy): MinimumSeed { - val n: Int = st.variableParameters() - val prec: MnMachinePrecision = st.precision() - - // initial starting values - val x: RealVector = ArrayRealVector(n) - for (i in 0 until n) { - x.setEntry(i, st.intParameters()[i]) - } - val fcnmin: Double = fcn.value(x) - val pa = MinimumParameters(x, fcnmin) - val igc = InitialGradientCalculator(fcn, st.getTransformation(), stra) - val dgrad: FunctionGradient = igc.gradient(pa) - val mat = MnAlgebraicSymMatrix(n) - val dcovar = 1.0 - for (i in 0 until n) { - mat[i, i] = if (abs(dgrad.getGradientDerivative() - .getEntry(i)) > prec.eps2() - ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0 - } - val err = MinimumError(mat, dcovar) - val edm: Double = VariableMetricEDMEstimator().estimate(dgrad, err) - val state = MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()) - return MinimumSeed(state, st.getTransformation()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SinParameterTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/SinParameterTransformation.kt deleted file mode 100644 index 821addef7..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SinParameterTransformation.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class SinParameterTransformation { - fun dInt2Ext(value: Double, upper: Double, lower: Double): Double { - return 0.5 * abs((upper - lower) * cos(value)) - } - - fun ext2int(value: Double, upper: Double, lower: Double, prec: MnMachinePrecision): Double { - val piby2: Double = 2.0 * atan(1.0) - val distnn: Double = 8.0 * sqrt(prec.eps2()) - val vlimhi = piby2 - distnn - val vlimlo = -piby2 + distnn - val yy = 2.0 * (value - lower) / (upper - lower) - 1.0 - val yy2 = yy * yy - return if (yy2 > 1.0 - prec.eps2()) { - if (yy < 0.0) { - vlimlo - } else { - vlimhi - } - } else { - asin(yy) - } - } - - fun int2ext(value: Double, upper: Double, lower: Double): Double { - return lower + 0.5 * (upper - lower) * (sin(value) + 1.0) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt deleted file mode 100644 index 444b63847..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class SqrtLowParameterTransformation { - // derivative of transformation from internal to external - fun dInt2Ext(value: Double, lower: Double): Double { - return value / sqrt(value * value + 1.0) - } - - // transformation from external to internal - fun ext2int(value: Double, lower: Double, prec: MnMachinePrecision): Double { - val yy = value - lower + 1.0 - val yy2 = yy * yy - return if (yy2 < 1.0 + prec.eps2()) { - 8 * sqrt(prec.eps2()) - } else { - sqrt(yy2 - 1) - } - } - - // transformation from internal to external - fun int2ext(value: Double, lower: Double): Double { - return lower - 1.0 + sqrt(value * value + 1.0) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt deleted file mode 100644 index 5774848bd..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class SqrtUpParameterTransformation { - // derivative of transformation from internal to external - fun dInt2Ext(value: Double, upper: Double): Double { - return -value / sqrt(value * value + 1.0) - } - - // transformation from external to internal - fun ext2int(value: Double, upper: Double, prec: MnMachinePrecision): Double { - val yy = upper - value + 1.0 - val yy2 = yy * yy - return if (yy2 < 1.0 + prec.eps2()) { - 8 * sqrt(prec.eps2()) - } else { - sqrt(yy2 - 1) - } - } - - // transformation from internal to external - fun int2ext(value: Double, upper: Double): Double { - return upper + 1.0 - sqrt(value * value + 1.0) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt deleted file mode 100644 index edc6783b6..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class VariableMetricBuilder : MinimumBuilder { - private val theErrorUpdator: DavidonErrorUpdator - private val theEstimator: VariableMetricEDMEstimator = VariableMetricEDMEstimator() - fun errorUpdator(): DavidonErrorUpdator { - return theErrorUpdator - } - - fun estimator(): VariableMetricEDMEstimator { - return theEstimator - } - - /** {@inheritDoc} */ - fun minimum( - fcn: MnFcn, - gc: GradientCalculator, - seed: MinimumSeed, - strategy: MnStrategy, - maxfcn: Int, - edmval: Double - ): FunctionMinimum { - val min: FunctionMinimum = minimum(fcn, gc, seed, maxfcn, edmval) - if (strategy.strategy() === 2 || strategy.strategy() === 1 && min.error().dcovar() > 0.05) { - val st: MinimumState = MnHesse(strategy).calculate(fcn, min.state(), min.seed().trafo(), 0) - min.add(st) - } - if (!min.isValid()) { - MINUITPlugin.logStatic("FunctionMinimum is invalid.") - } - return min - } - - fun minimum(fcn: MnFcn, gc: GradientCalculator, seed: MinimumSeed, maxfcn: Int, edmval: Double): FunctionMinimum { - var edmval = edmval - edmval *= 0.0001 - if (seed.parameters().vec().getDimension() === 0) { - return FunctionMinimum(seed, fcn.errorDef()) - } - val prec: MnMachinePrecision = seed.precision() - val result: MutableList = java.util.ArrayList(8) - var edm: Double = seed.state().edm() - if (edm < 0.0) { - MINUITPlugin.logStatic("VariableMetricBuilder: initial matrix not pos.def.") - if (seed.error().isPosDef()) { - throw RuntimeException("Something is wrong!") - } - return FunctionMinimum(seed, fcn.errorDef()) - } - result.add(seed.state()) - - // iterate until edm is small enough or max # of iterations reached - edm *= 1.0 + 3.0 * seed.error().dcovar() - var step: RealVector // = new ArrayRealVector(seed.gradient().getGradient().getDimension()); - do { - var s0: MinimumState = result[result.size - 1] - step = MnUtils.mul(MnUtils.mul(s0.error().invHessian(), s0.gradient().getGradient()), -1) - var gdel: Double = MnUtils.innerProduct(step, s0.gradient().getGradient()) - if (gdel > 0.0) { - MINUITPlugin.logStatic("VariableMetricBuilder: matrix not pos.def.") - MINUITPlugin.logStatic("gdel > 0: $gdel") - s0 = MnPosDef.test(s0, prec) - step = MnUtils.mul(MnUtils.mul(s0.error().invHessian(), s0.gradient().getGradient()), -1) - gdel = MnUtils.innerProduct(step, s0.gradient().getGradient()) - MINUITPlugin.logStatic("gdel: $gdel") - if (gdel > 0.0) { - result.add(s0) - return FunctionMinimum(seed, result, fcn.errorDef()) - } - } - val pp: MnParabolaPoint = MnLineSearch.search(fcn, s0.parameters(), step, gdel, prec) - if (abs(pp.y() - s0.fval()) < prec.eps()) { - MINUITPlugin.logStatic("VariableMetricBuilder: no improvement") - break //no improvement - } - val p = MinimumParameters(MnUtils.add(s0.vec(), MnUtils.mul(step, pp.x())), pp.y()) - val g: FunctionGradient = gc.gradient(p, s0.gradient()) - edm = estimator().estimate(g, s0.error()) - if (edm < 0.0) { - MINUITPlugin.logStatic("VariableMetricBuilder: matrix not pos.def.") - MINUITPlugin.logStatic("edm < 0") - s0 = MnPosDef.test(s0, prec) - edm = estimator().estimate(g, s0.error()) - if (edm < 0.0) { - result.add(s0) - return FunctionMinimum(seed, result, fcn.errorDef()) - } - } - val e: MinimumError = errorUpdator().update(s0, p, g) - result.add(MinimumState(p, e, g, edm, fcn.numOfCalls())) - // result[0] = MinimumState(p, e, g, edm, fcn.numOfCalls()); - edm *= 1.0 + 3.0 * e.dcovar() - } while (edm > edmval && fcn.numOfCalls() < maxfcn) - if (fcn.numOfCalls() >= maxfcn) { - MINUITPlugin.logStatic("VariableMetricBuilder: call limit exceeded.") - return FunctionMinimum(seed, result, fcn.errorDef(), MnReachedCallLimit()) - } - return if (edm > edmval) { - if (edm < abs(prec.eps2() * result[result.size - 1].fval())) { - MINUITPlugin.logStatic("VariableMetricBuilder: machine accuracy limits further improvement.") - FunctionMinimum(seed, result, fcn.errorDef()) - } else if (edm < 10.0 * edmval) { - FunctionMinimum(seed, result, fcn.errorDef()) - } else { - MINUITPlugin.logStatic("VariableMetricBuilder: finishes without convergence.") - MINUITPlugin.logStatic("VariableMetricBuilder: edm= $edm requested: $edmval") - FunctionMinimum(seed, result, fcn.errorDef(), MnAboveMaxEdm()) - } - } else FunctionMinimum(seed, result, fcn.errorDef()) - } - - init { - theErrorUpdator = DavidonErrorUpdator() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt deleted file mode 100644 index 8fca4e6ee..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @author tonyj - * @version $Id$ - */ -internal class VariableMetricEDMEstimator { - fun estimate(g: FunctionGradient, e: MinimumError): Double { - if (e.invHessian().size() === 1) { - return 0.5 * g.getGradient().getEntry(0) * g.getGradient().getEntry(0) * e.invHessian()[0, 0] - } - val rho: Double = MnUtils.similarity(g.getGradient(), e.invHessian()) - return 0.5 * rho - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt deleted file mode 100644 index 2a13a5fff..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class VariableMetricMinimizer : ModularFunctionMinimizer() { - private val theMinBuilder: VariableMetricBuilder - private val theMinSeedGen: MnSeedGenerator = MnSeedGenerator() - - /** {@inheritDoc} */ - override fun builder(): MinimumBuilder { - return theMinBuilder - } - - /** {@inheritDoc} */ - override fun seedGenerator(): MinimumSeedGenerator { - return theMinSeedGen - } - - /** - * - * Constructor for VariableMetricMinimizer. - */ - init { - theMinBuilder = VariableMetricBuilder() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/package-info.kt b/kmath-optimization/src/commonMain/tmp/minuit/package-info.kt deleted file mode 100644 index 22779da86..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/package-info.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - diff --git a/kmath-stat/README.md b/kmath-stat/README.md deleted file mode 100644 index e7e0a4d92..000000000 --- a/kmath-stat/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-stat - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-stat:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-stat:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-stat:0.4.0-dev-1") -} -``` diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index 000280def..dff504ef0 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -1,22 +1,27 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity + plugins { - id("space.kscience.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") } -kscience{ - jvm() - js() - native() +kscience { + useAtomic() } kotlin.sourceSets { commonMain { dependencies { - api(projects.kmathCoroutines) - //implementation(spclibs.atomicfu) + api(project(":kmath-coroutines")) } } - getByName("jvmMain") { + jvmMain { dependencies { api("org.apache.commons:commons-rng-sampling:1.3") api("org.apache.commons:commons-rng-simple:1.3") @@ -25,5 +30,5 @@ kotlin.sourceSets { } readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + maturity = Maturity.EXPERIMENTAL } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt index 806da5560..e3adcdc44 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt @@ -1,12 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.distributions import space.kscience.kmath.chains.Chain -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.Sampler /** @@ -19,15 +19,15 @@ public interface Distribution : Sampler { */ public fun probability(arg: T): Double - override fun sample(generator: RandomGenerator): Chain + public override fun sample(generator: RandomGenerator): Chain /** - * An empty companion. Distribution factories should be written as its extensions. + * An empty companion. Distribution factories should be written as its extensions */ public companion object } -public interface Distribution1D> : Distribution { +public interface UnivariateDistribution> : Distribution { /** * Cumulative distribution for ordered parameter (CDF) */ @@ -37,7 +37,7 @@ public interface Distribution1D> : Distribution { /** * Compute probability integral in an interval */ -public fun > Distribution1D.integral(from: T, to: T): Double { +public fun > UnivariateDistribution.integral(from: T, to: T): Double { require(to > from) return cumulative(to) - cumulative(from) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt index 999fbffbc..dde429244 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,15 +7,15 @@ package space.kscience.kmath.distributions import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.SimpleChain -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.RandomGenerator /** - * A multivariate distribution that takes a map of parameters. + * A multivariate distribution which takes a map of parameters */ public interface NamedDistribution : Distribution> /** - * A multivariate distribution that has independent distributions for separate axis. + * A multivariate distribution that has independent distributions for separate axis */ public class FactorizedDistribution(public val distributions: Collection>) : NamedDistribution { diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt index ae814254b..04ec8b171 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt @@ -1,32 +1,36 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.distributions import space.kscience.kmath.chains.Chain -import space.kscience.kmath.operations.DoubleField.pow -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.internal.InternalErf import space.kscience.kmath.samplers.GaussianSampler -import space.kscience.kmath.samplers.InternalErf import space.kscience.kmath.samplers.NormalizedGaussianSampler import space.kscience.kmath.samplers.ZigguratNormalizedGaussianSampler +import space.kscience.kmath.stat.RandomGenerator import kotlin.math.* /** - * Implements [Distribution1D] for the normal (gaussian) distribution. + * Implements [UnivariateDistribution] for the normal (gaussian) distribution. */ -public class NormalDistribution(public val sampler: GaussianSampler) : Distribution1D { +public class NormalDistribution(public val sampler: GaussianSampler) : UnivariateDistribution { + public constructor( + mean: Double, + standardDeviation: Double, + normalized: NormalizedGaussianSampler = ZigguratNormalizedGaussianSampler, + ) : this(GaussianSampler(mean, standardDeviation, normalized)) - override fun probability(arg: Double): Double { + public override fun probability(arg: Double): Double { val x1 = (arg - sampler.mean) / sampler.standardDeviation return exp(-0.5 * x1 * x1 - (ln(sampler.standardDeviation) + 0.5 * ln(2 * PI))) } - override fun sample(generator: RandomGenerator): Chain = sampler.sample(generator) + public override fun sample(generator: RandomGenerator): Chain = sampler.sample(generator) - override fun cumulative(arg: Double): Double { + public override fun cumulative(arg: Double): Double { val dev = arg - sampler.mean return when { @@ -35,28 +39,7 @@ public class NormalDistribution(public val sampler: GaussianSampler) : Distribut } } - public companion object { + private companion object { private val SQRT2 = sqrt(2.0) - - /** - * Zelen & Severo approximation for the standard normal CDF. - * The error upper boundary by 7.5 * 10e-8. - */ - public fun zSNormalCDF(x: Double): Double { - val t = 1 / (1 + 0.2316419 * abs(x)) - val sum = 0.319381530 * t - - 0.356563782 * t.pow(2) + - 1.781477937 * t.pow(3) - - 1.821255978 * t.pow(4) + - 1.330274429 * t.pow(5) - val temp = sum * exp(-abs(x).pow(2) / 2) / (2 * PI).pow(0.5) - return if (x >= 0) 1 - temp else temp - } } } - -public fun NormalDistribution( - mean: Double, - standardDeviation: Double, - normalized: NormalizedGaussianSampler = ZigguratNormalizedGaussianSampler, -): NormalDistribution = NormalDistribution(GaussianSampler(mean, standardDeviation, normalized)) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalErf.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt similarity index 87% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalErf.kt rename to kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt index 0c1a5b36f..25668446c 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalErf.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.samplers +package space.kscience.kmath.internal import kotlin.math.abs diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalGamma.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt similarity index 97% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalGamma.kt rename to kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt index 43c5a0d3c..a584af4f9 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalGamma.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.samplers +package space.kscience.kmath.internal import kotlin.math.* @@ -110,7 +110,7 @@ internal object InternalGamma { x <= 8.0 -> { val n = floor(x - 1.5).toInt() - val prod = (1..n).fold(1.0) { prod, i -> prod * (x - i) } + val prod = (1..n).fold(1.0, { prod, i -> prod * (x - i) }) logGamma1p(x - (n + 1)) + ln(prod) } @@ -145,7 +145,7 @@ internal object InternalGamma { } when { - n >= maxIterations -> error("Maximal iterations is exceeded $maxIterations") + n >= maxIterations -> throw error("Maximal iterations is exceeded $maxIterations") sum.isInfinite() -> 1.0 else -> exp(-x + a * ln(x) - logGamma(a)) * sum } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalUtils.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt similarity index 93% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalUtils.kt rename to kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt index 9f633e3db..3997a77b3 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalUtils.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.samplers +package space.kscience.kmath.internal import kotlin.math.ln import kotlin.math.min @@ -48,8 +48,7 @@ internal object InternalUtils { cache.copyInto( logFactorials, BEGIN_LOG_FACTORIALS, - BEGIN_LOG_FACTORIALS, - endCopy, + BEGIN_LOG_FACTORIALS, endCopy ) } else // All values to be computed diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt new file mode 100644 index 000000000..38f3038c2 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.expressions.AutoDiffProcessor +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.ExpressionAlgebra +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.indices + +/** + * A likelihood function optimization problem with provided derivatives + */ +public interface FunctionOptimization : Optimization { + /** + * The optimization direction. If true search for function maximum, if false, search for the minimum + */ + public var maximize: Boolean + + /** + * Define the initial guess for the optimization problem + */ + public fun initialGuess(map: Map) + + /** + * Set a differentiable expression as objective function as function and gradient provider + */ + public fun diffFunction(expression: DifferentiableExpression>) + + public companion object { + /** + * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation + */ + public fun chiSquared( + autoDiff: AutoDiffProcessor>, + x: Buffer, + y: Buffer, + yErr: Buffer, + model: A.(I) -> I, + ): DifferentiableExpression> where A : ExtendedField, A : ExpressionAlgebra { + require(x.size == y.size) { "X and y buffers should be of the same size" } + require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } + + return autoDiff.process { + var sum = zero + + x.indices.forEach { + val xValue = const(x[it]) + val yValue = const(y[it]) + val yErrValue = const(yErr[it]) + val modelValue = model(xValue) + sum += ((yValue - modelValue) / yErrValue).pow(2) + } + + sum + } + } + } +} + +/** + * Define a chi-squared-based objective function + */ +public fun FunctionOptimization.chiSquared( + autoDiff: AutoDiffProcessor>, + x: Buffer, + y: Buffer, + yErr: Buffer, + model: A.(I) -> I, +) where A : ExtendedField, A : ExpressionAlgebra { + val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) + diffFunction(chiSquared) + maximize = false +} + +/** + * Optimize differentiable expression using specific [OptimizationProblemFactory] + */ +public fun > DifferentiableExpression>.optimizeWith( + factory: OptimizationProblemFactory, + vararg symbols: Symbol, + configuration: F.() -> Unit, +): OptimizationResult { + require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } + val problem = factory(symbols.toList(), configuration) + problem.diffFunction(this) + return problem.optimize() +} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt new file mode 100644 index 000000000..67a21bf2a --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.indices +import kotlin.math.pow + +/** + * A likelihood function optimization problem + */ +public interface NoDerivFunctionOptimization : Optimization { + /** + * The optimization direction. If true search for function maximum, if false, search for the minimum + */ + public var maximize: Boolean + + /** + * Define the initial guess for the optimization problem + */ + public fun initialGuess(map: Map) + + /** + * Set an objective function expression + */ + public fun function(expression: Expression) + + public companion object { + /** + * Generate a chi squared expression from given x-y-sigma model represented by an expression. Does not provide derivatives + */ + public fun chiSquared( + x: Buffer, + y: Buffer, + yErr: Buffer, + model: Expression, + xSymbol: Symbol = Symbol.x, + ): Expression { + require(x.size == y.size) { "X and y buffers should be of the same size" } + require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } + + return Expression { arguments -> + x.indices.sumOf { + val xValue = x[it] + val yValue = y[it] + val yErrValue = yErr[it] + val modifiedArgs = arguments + (xSymbol to xValue) + val modelValue = model(modifiedArgs) + ((yValue - modelValue) / yErrValue).pow(2) + } + } + } + } +} + + +/** + * Optimize expression without derivatives using specific [OptimizationProblemFactory] + */ +public fun > Expression.noDerivOptimizeWith( + factory: OptimizationProblemFactory, + vararg symbols: Symbol, + configuration: F.() -> Unit, +): OptimizationResult { + require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } + val problem = factory(symbols.toList(), configuration) + problem.function(this) + return problem.optimize() +} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt new file mode 100644 index 000000000..3b9868815 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.misc.Symbol + +public interface OptimizationFeature + +public class OptimizationResult( + public val point: Map, + public val value: T, + public val features: Set = emptySet(), +) { + override fun toString(): String { + return "OptimizationResult(point=$point, value=$value)" + } +} + +public operator fun OptimizationResult.plus( + feature: OptimizationFeature, +): OptimizationResult = OptimizationResult(point, value, features + feature) + +/** + * An optimization problem builder over [T] variables + */ +public interface Optimization { + + /** + * Update the problem from previous optimization run + */ + public fun update(result: OptimizationResult) + + /** + * Make an optimization run + */ + public fun optimize(): OptimizationResult +} + +public fun interface OptimizationProblemFactory> { + public fun build(symbols: List): P +} + +public operator fun > OptimizationProblemFactory.invoke( + symbols: List, + block: P.() -> Unit, +): P = build(symbols).apply(block) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt new file mode 100644 index 000000000..f5cfa05e6 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.data.ColumnarData +import space.kscience.kmath.expressions.AutoDiffProcessor +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.ExpressionAlgebra +import space.kscience.kmath.misc.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.Field + +@UnstableKMathAPI +public interface XYFit : Optimization { + + public val algebra: Field + + /** + * Set X-Y data for this fit optionally including x and y errors + */ + public fun data( + dataSet: ColumnarData, + xSymbol: Symbol, + ySymbol: Symbol, + xErrSymbol: Symbol? = null, + yErrSymbol: Symbol? = null, + ) + + public fun model(model: (T) -> DifferentiableExpression) + + /** + * Set the differentiable model for this fit + */ + public fun model( + autoDiff: AutoDiffProcessor>, + modelFunction: A.(I) -> I, + ): Unit where A : ExtendedField, A : ExpressionAlgebra = model { arg -> + autoDiff.process { modelFunction(const(arg)) } + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt index e5a48d4d8..a231842df 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt @@ -1,12 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.Sampler import space.kscience.kmath.structures.DoubleBuffer import kotlin.math.ln @@ -24,7 +24,7 @@ public class AhrensDieterExponentialSampler(public val mean: Double) : Sampler 0) { "mean is not strictly positive: $mean" } } - override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { + public override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { override fun nextBlocking(): Double { // Step 1: var a = 0.0 @@ -67,7 +67,7 @@ public class AhrensDieterExponentialSampler(public val mean: Double) : Sampler - qi += ln2.pow(i + 1.0) / InternalUtils.factorial(i + 1) + qi += ln2.pow(i + 1.0) / space.kscience.kmath.internal.InternalUtils.factorial(i + 1) qi } } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt index d301ff637..2f32eee85 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt @@ -1,22 +1,22 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers import space.kscience.kmath.chains.Chain -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.random.chain +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.Sampler +import space.kscience.kmath.stat.chain import space.kscience.kmath.stat.next import kotlin.math.* /** * Sampling from the [gamma distribution](http://mathworld.wolfram.com/GammaDistribution.html). - * * For 0 < alpha < 1: + * - For 0 < alpha < 1: * Ahrens, J. H. and Dieter, U., Computer methods for sampling from gamma, beta, Poisson and binomial distributions, Computing, 12, 223-246, 1974. - * * For alpha >= 1: + * - For alpha >= 1: * Marsaglia and Tsang, A Simple Method for Generating Gamma Variables. ACM Transactions on Mathematical Software, Volume 26 Issue 3, September, 2000. * * Based on Commons RNG implementation. @@ -25,14 +25,14 @@ import kotlin.math.* */ public class AhrensDieterMarsagliaTsangGammaSampler private constructor( alpha: Double, - theta: Double, + theta: Double ) : Sampler { private val delegate: BaseGammaSampler = if (alpha < 1) AhrensDieterGammaSampler(alpha, theta) else MarsagliaTsangGammaSampler(alpha, theta) private abstract class BaseGammaSampler internal constructor( protected val alpha: Double, - protected val theta: Double, + protected val theta: Double ) : Sampler { init { require(alpha > 0) { "alpha is not strictly positive: $alpha" } @@ -113,13 +113,13 @@ public class AhrensDieterMarsagliaTsangGammaSampler private constructor( } } - override fun sample(generator: RandomGenerator): Chain = delegate.sample(generator) - override fun toString(): String = delegate.toString() + public override fun sample(generator: RandomGenerator): Chain = delegate.sample(generator) + public override fun toString(): String = delegate.toString() public companion object { public fun of( alpha: Double, - theta: Double, + theta: Double ): Sampler = AhrensDieterMarsagliaTsangGammaSampler(alpha, theta) } } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt index 2ec40c347..db4f598b7 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt @@ -1,14 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers import space.kscience.kmath.chains.Chain -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.random.chain +import space.kscience.kmath.internal.InternalUtils +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.Sampler +import space.kscience.kmath.stat.chain import kotlin.math.ceil import kotlin.math.max import kotlin.math.min @@ -19,7 +20,7 @@ import kotlin.math.min * implements Vose's algorithm. * * Vose, M.D., A linear algorithm for generating random numbers with a given distribution, IEEE Transactions on - * Software Engineering, 17, 972-975, 1991. The algorithm will sample values in O(1) time after a pre-processing step + * Software Engineering, 17, 972-975, 1991. he algorithm will sample values in O(1) time after a pre-processing step * of O(n) time. * * The alias tables are constructed using fraction probabilities with an assumed denominator of 253. In the generic @@ -75,8 +76,8 @@ public open class AliasMethodDiscreteSampler private constructor( } } - override fun sample(generator: RandomGenerator): Chain = generator.chain { - // This implements the algorithm in accordance with Vose (1991): + public override fun sample(generator: RandomGenerator): Chain = generator.chain { + // This implements the algorithm as per Vose (1991): // v = uniform() in [0, 1) // j = uniform(n) in [0, n) // if v < prob[j] then @@ -94,7 +95,7 @@ public open class AliasMethodDiscreteSampler private constructor( // p(j) == 1 => j // However it is assumed these edge cases are rare: // - // The probability table will be 1 for approximately 1/n samples i.e., only the + // The probability table will be 1 for approximately 1/n samples, i.e. only the // last unpaired probability. This is only worth checking for when the table size (n) // is small. But in that case the user should zero-pad the table for performance. // @@ -106,7 +107,7 @@ public open class AliasMethodDiscreteSampler private constructor( if (generator.nextLong() ushr 11 < probability[j]) j else alias[j] } - override fun toString(): String = "Alias method" + public override fun toString(): String = "Alias method" public companion object { private const val DEFAULT_ALPHA = 0 @@ -210,7 +211,7 @@ public open class AliasMethodDiscreteSampler private constructor( // c: 2=2/3; 6=1/3 (6 is the alias) // d: 1=1/3; 6=2/3 (6 is the alias) // - // The sample is obtained by randomly selecting a section, then choosing, which category + // The sample is obtained by randomly selecting a section, then choosing which category // from the pair based on a uniform random deviate. val sumProb = InternalUtils.validateProbabilities(probabilities) // Allow zero-padding @@ -240,9 +241,9 @@ public open class AliasMethodDiscreteSampler private constructor( val alias = IntArray(n) // This loop uses each large in turn to fill the alias table for small probabilities that - // do not reach the requirement to fill an entire section alone (i.e., p < mean). + // do not reach the requirement to fill an entire section alone (i.e. p < mean). // Since the sum of the small should be less than the sum of the large it should use up - // all the small first. However, floating point round-off can result in + // all the small first. However floating point round-off can result in // misclassification of items as small or large. The Vose algorithm handles this using // a while loop conditioned on the size of both sets and a subsequent loop to use // unpaired items. diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt index 7795ff297..b3c014553 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt @@ -1,12 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.DoubleBuffer import kotlin.math.* diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.kt new file mode 100644 index 000000000..0d38fe19b --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.samplers + +import space.kscience.kmath.chains.BlockingBufferChain +import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.stat.Sampler +import space.kscience.kmath.structures.Buffer + +public class ConstantSampler(public val const: T) : Sampler { + override fun sample(generator: RandomGenerator): BlockingBufferChain = object : BlockingBufferChain { + override fun nextBufferBlocking(size: Int): Buffer = Buffer.boxing(size) { const } + override suspend fun fork(): BlockingBufferChain = this + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt index 28d588165..d7d8e87b7 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,7 +7,7 @@ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain import space.kscience.kmath.chains.map -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.RandomGenerator /** * Sampling from a Gaussian distribution with given mean and standard deviation. @@ -21,14 +21,14 @@ import space.kscience.kmath.random.RandomGenerator public class GaussianSampler( public val mean: Double, public val standardDeviation: Double, - private val normalized: NormalizedGaussianSampler = BoxMullerSampler, + private val normalized: NormalizedGaussianSampler = BoxMullerSampler ) : BlockingDoubleSampler { init { require(standardDeviation > 0.0) { "standard deviation is not strictly positive: $standardDeviation" } } - override fun sample(generator: RandomGenerator): BlockingDoubleChain = normalized + public override fun sample(generator: RandomGenerator): BlockingDoubleChain = normalized .sample(generator) .map { standardDeviation * it + mean } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt index 6d2899314..9bb48fe4e 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt @@ -1,19 +1,19 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingIntChain -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.Sampler import space.kscience.kmath.structures.IntBuffer import kotlin.math.exp /** * Sampler for the Poisson distribution. - * * Kemp, A, W, (1981) Efficient Generation of Logarithmically Distributed Pseudo-Random Variables. Journal of the Royal Statistical Society. Vol. 30, No. 3, pp. 249-253. + * - Kemp, A, W, (1981) Efficient Generation of Logarithmically Distributed Pseudo-Random Variables. Journal of the Royal Statistical Society. Vol. 30, No. 3, pp. 249-253. * This sampler is suitable for mean < 40. For large means, LargeMeanPoissonSampler should be used instead. * * Note: The algorithm uses a recurrence relation to compute the Poisson probability and a rolling summation for the cumulative probability. When the mean is large the initial probability (Math.exp(-mean)) is zero and an exception is raised by the constructor. @@ -27,7 +27,7 @@ public class KempSmallMeanPoissonSampler internal constructor( private val p0: Double, private val mean: Double, ) : Sampler { - override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { + public override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { override fun nextBlocking(): Int { //TODO move to nextBufferBlocking // Note on the algorithm: @@ -60,13 +60,14 @@ public class KempSmallMeanPoissonSampler internal constructor( override suspend fun fork(): BlockingIntChain = sample(generator.fork()) } - override fun toString(): String = "Kemp Small Mean Poisson deviate" + public override fun toString(): String = "Kemp Small Mean Poisson deviate" } public fun KempSmallMeanPoissonSampler(mean: Double): KempSmallMeanPoissonSampler { require(mean > 0) { "Mean is not strictly positive: $mean" } val p0 = exp(-mean) - // Probability must be positive. As mean increases, p(0) decreases. + // Probability must be positive. As mean increases then p(0) decreases. require(p0 > 0) { "No probability for mean: $mean" } return KempSmallMeanPoissonSampler(p0, mean) } + diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt index 3c3fe10fd..0a68e5c88 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt @@ -1,12 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.DoubleBuffer import kotlin.math.ln import kotlin.math.sqrt diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt index 291d0bffe..83f87e832 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt @@ -1,15 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.Sampler -public interface BlockingDoubleSampler : Sampler { +public interface BlockingDoubleSampler: Sampler{ override fun sample(generator: RandomGenerator): BlockingDoubleChain } @@ -18,6 +18,6 @@ public interface BlockingDoubleSampler : Sampler { * Marker interface for a sampler that generates values from an N(0,1) * [Gaussian distribution](https://en.wikipedia.org/wiki/Normal_distribution). */ -public fun interface NormalizedGaussianSampler : BlockingDoubleSampler { +public fun interface NormalizedGaussianSampler : BlockingDoubleSampler{ public companion object } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt index 454691e05..e95778b9e 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt @@ -1,13 +1,13 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingIntChain -import space.kscience.kmath.misc.toIntExact -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.internal.InternalUtils +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.Sampler import space.kscience.kmath.structures.IntBuffer import kotlin.math.* @@ -17,11 +17,11 @@ private const val PIVOT = 40.0 /** * Sampler for the Poisson distribution. - * * For small means, a Poisson process is simulated using uniform deviates, as described in + * - For small means, a Poisson process is simulated using uniform deviates, as described in * Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3 * Important integer-valued distributions: The Poisson distribution. Addison Wesley. * The Poisson process (and hence, the returned value) is bounded by 1000 * mean. - * * For large means, we use the rejection algorithm described in + * - For large means, we use the rejection algorithm described in * Devroye, Luc. (1981). The Computer Generation of Poisson Random Variables Computing vol. 26 pp. 197-207. * * Based on Commons RNG implementation. @@ -34,10 +34,10 @@ public fun PoissonSampler(mean: Double): Sampler { /** * Sampler for the Poisson distribution. - * * For small means, a Poisson process is simulated using uniform deviates, as described in + * - For small means, a Poisson process is simulated using uniform deviates, as described in * Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3 Important * integer-valued distributions: The Poisson distribution. Addison Wesley. - * * The Poisson process (and hence, the returned value) is bounded by 1000 * mean. + * - The Poisson process (and hence, the returned value) is bounded by 1000 * mean. * This sampler is suitable for mean < 40. For large means, [LargeMeanPoissonSampler] should be used instead. * * Based on Commons RNG implementation. @@ -58,7 +58,7 @@ public class SmallMeanPoissonSampler(public val mean: Double) : Sampler { throw IllegalArgumentException("No p(x=0) probability for mean: $mean") }.toInt() - override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { + public override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { override fun nextBlocking(): Int { var n = 0 var r = 1.0 @@ -76,7 +76,7 @@ public class SmallMeanPoissonSampler(public val mean: Double) : Sampler { override suspend fun fork(): BlockingIntChain = sample(generator.fork()) } - override fun toString(): String = "Small Mean Poisson deviate" + public override fun toString(): String = "Small Mean Poisson deviate" } @@ -113,13 +113,13 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { private val p1: Double = a1 / aSum private val p2: Double = a2 / aSum - override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { + public override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { override fun nextBlocking(): Int { val exponential = AhrensDieterExponentialSampler(1.0).sample(generator) val gaussian = ZigguratNormalizedGaussianSampler.sample(generator) val smallMeanPoissonSampler = if (mean - lambda < Double.MIN_VALUE) { - null + null } else { KempSmallMeanPoissonSampler(mean - lambda).sample(generator) } @@ -188,7 +188,7 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { } } - return min(y2 + y.toLong(), Int.MAX_VALUE.toLong()).toIntExact() + return min(y2 + y.toLong(), Int.MAX_VALUE.toLong()).toInt() } override fun nextBufferBlocking(size: Int): IntBuffer = IntBuffer(size) { nextBlocking() } @@ -197,7 +197,7 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { } private fun getFactorialLog(n: Int): Double = factorialLog.value(n) - override fun toString(): String = "Large Mean Poisson deviate" + public override fun toString(): String = "Large Mean Poisson deviate" public companion object { private const val MAX_MEAN: Double = 0.5 * Int.MAX_VALUE diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/SamplerAlgebra.kt deleted file mode 100644 index 44b87a431..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/SamplerAlgebra.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.ConstantChain -import space.kscience.kmath.chains.map -import space.kscience.kmath.chains.zip -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.stat.Sampler - -/** - * Implements [Sampler] by sampling only certain [value]. - * - * @property value the value to sample. - */ -public class ConstantSampler(public val value: T) : Sampler { - override fun sample(generator: RandomGenerator): Chain = ConstantChain(value) -} - -/** - * Implements [Sampler] by delegating sampling to value of [chainBuilder]. - * - * @property chainBuilder the provider of [Chain]. - */ -public class BasicSampler(public val chainBuilder: (RandomGenerator) -> Chain) : Sampler { - override fun sample(generator: RandomGenerator): Chain = chainBuilder(generator) -} - -/** - * A space of samplers. Allows performing simple operations on distributions. - * - * @property algebra the space to provide addition and scalar multiplication for [T]. - */ -public class SamplerSpace(public val algebra: S) : Group>, - ScaleOperations> where S : Group, S : ScaleOperations { - - override val zero: Sampler = ConstantSampler(algebra.zero) - - override fun add(left: Sampler, right: Sampler): Sampler = BasicSampler { generator -> - left.sample(generator).zip(right.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } } - } - - override fun scale(a: Sampler, value: Double): Sampler = BasicSampler { generator -> - a.sample(generator).map { a -> - algebra { a * value } - } - } - - override fun Sampler.unaryMinus(): Sampler = scale(this, -1.0) -} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt index 40ce37d15..24148271d 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt @@ -1,12 +1,12 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.DoubleBuffer import kotlin.math.* diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt deleted file mode 100644 index ed6f4e07b..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.series - -import space.kscience.kmath.operations.BufferAlgebra -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.structures.Buffer -import kotlin.math.ceil -import kotlin.math.floor - -/** - * A [SeriesAlgebra] with reverse label to index transformation. - * - * @param [labelToOffset] returns floating point number that is used for index resolution. - */ -public class MonotonicSeriesAlgebra, out BA : BufferAlgebra, L : Comparable>( - bufferAlgebra: BA, - offsetToLabel: (Int) -> L, - private val labelToOffset: (L) -> Double, -) : SeriesAlgebra(bufferAlgebra, offsetToLabel) { - - public val Buffer.labelRange: ClosedRange get() = offsetToLabel(startOffset)..offsetToLabel(startOffset + size) - - /** - * An offset of the given [label] rounded down - */ - public fun floorOffset(label: L): Int = floor(labelToOffset(label)).toInt() - - /** - * An offset of the given [label] rounded up - */ - public fun ceilOffset(label: L): Int = ceil(labelToOffset(label)).toInt() - - /** - * Get value by label (rounded down) or return null if the value is outside series boundaries. - */ - override fun Buffer.getByLabelOrNull(label: L): T? = getByOffsetOrNull(floorOffset(label)) -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt deleted file mode 100644 index cabff25e6..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt +++ /dev/null @@ -1,238 +0,0 @@ -package space.kscience.kmath.series - -import space.kscience.kmath.operations.BufferAlgebra -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.RingOps -import space.kscience.kmath.stat.StatisticalAlgebra -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferView -import space.kscience.kmath.structures.getOrNull -import kotlin.math.max -import kotlin.math.min - -@PublishedApi -internal fun IntRange.intersect(other: IntRange): IntRange = - max(first, other.first)..min(last, other.last) - -@PublishedApi -internal val IntRange.size: Int - get() = last - first + 1 - -@PublishedApi -internal operator fun IntRange.contains(other: IntRange): Boolean = (other.first in this) && (other.last in this) - -//TODO add permutation sort -//TODO check rank statistics - -/** - * A [Buffer] with an offset relative to the [SeriesAlgebra] zero. - */ -public interface Series : Buffer { - public val origin: Buffer - - /** - * Absolute position of start of this [Series] in [SeriesAlgebra] - */ - public val position: Int -} - -/** - * A [BufferView] with index offset (both positive and negative) and possible size change - */ -private class SeriesImpl( - override val origin: Buffer, - override val position: Int, - override val size: Int = origin.size, -) : Series, Buffer by origin { - - init { - require(size > 0) { "Size must be positive" } - require(size <= origin.size) { "Slice size is larger than the original buffer" } - } - - override fun toString(): String = "$origin-->${position}" -} - -/** - * A scope to operation on series - */ -public open class SeriesAlgebra, out BA : BufferAlgebra, L>( - override val bufferAlgebra: BA, - public val offsetToLabel: (Int) -> L, -) : RingOps>, StatisticalAlgebra { - - /** - * A range of valid offset indices. In general, does not start with zero. - */ - public val Buffer.offsetIndices: IntRange - get() = if (this is Series) { - position until position + size - } else { - 0 until size - } - - /** - * Get the value by absolute offset in the series algebra or return null if index is out of range - */ - public fun Buffer.getByOffsetOrNull(index: Int): T? = when { - index !in offsetIndices -> null - this is Series -> origin.getOrNull(index - position) - else -> getOrNull(index) - } - - /** - * Get the value by absolute index in the series algebra or throw [IndexOutOfBoundsException] if index is out of range - */ - public fun Buffer.getByOffset(index: Int): T = - getByOffsetOrNull(index) ?: throw IndexOutOfBoundsException("Index $index is not in $offsetIndices") - - /** - * Zero-copy move [Buffer] or [Series] to given [position] ignoring series offset if it is present. - */ - public fun Buffer.moveTo(position: Int): Series = if (this is Series) { - SeriesImpl(origin, position, size) - } else { - SeriesImpl(this, position, size) - } - - /** - * Zero-copy move [Buffer] or [Series] by given [offset]. If it is [Series], sum intrinsic series position and the [offset]. - */ - public fun Buffer.moveBy(offset: Int): Series = if (this is Series) { - SeriesImpl(origin, position + offset, size) - } else { - SeriesImpl(this, offset, size) - } - - /** - * An offset of the buffer start relative to [SeriesAlgebra] zero offset - */ - public val Buffer.startOffset: Int get() = if (this is Series) position else 0 - - public val Buffer.startLabel: L get() = offsetToLabel(startOffset) - - /** - * Build a new series by offset positioned at [startOffset]. - */ - public inline fun seriesByOffset( - size: Int, - startOffset: Int = 0, - crossinline block: A.(offset: Int) -> T, - ): Series = elementAlgebra.bufferFactory(size) { - elementAlgebra.block(it + startOffset) - }.moveTo(startOffset) - - /** - * Build a new series by label positioned at [startOffset]. - */ - public inline fun series(size: Int, startOffset: Int = 0, crossinline block: A.(label: L) -> T): Series = - seriesByOffset(size, startOffset) { offset -> block(offsetToLabel(offset)) } - - /** - * Get a label buffer for given buffer. - */ - public val Buffer.labels: List get() = offsetIndices.map(offsetToLabel) - - /** - * Try to resolve element by label and return null if element with a given label is not found - */ - public open fun Buffer.getByLabelOrNull(label: L): T? { - val index = labels.indexOf(label) - if (index == -1) return null - return getByOffset(index + startOffset) - } - - /** - * Get value by label (rounded down) or throw [IndexOutOfBoundsException] if the value is outside series boundaries. - */ - public open fun Buffer.getByLabel(label: L): T = getByLabelOrNull(label) - ?: throw IndexOutOfBoundsException("Label $label is not in ${labels.first()}..${labels.last()}") - - /** - * Map a series to another series of the same size - */ - public inline fun Buffer.map(crossinline transform: A.(T) -> T): Series { - val buf = elementAlgebra.bufferFactory(size) { - elementAlgebra.transform(get(it)) - } - return buf.moveTo(offsetIndices.first) - } - - /** - * Map series to another series of the same size with label - */ - public inline fun Buffer.mapWithLabel(crossinline transform: A.(arg: T, label: L) -> T): Series { - val labels = labels - val buf = elementAlgebra.bufferFactory(size) { - elementAlgebra.transform(getByOffset(it), labels[it]) - } - return buf.moveTo(offsetIndices.first) - } - - public inline fun Buffer.fold(initial: R, operation: A.(acc: R, T) -> R): R { - var accumulator = initial - for (index in this.offsetIndices) accumulator = elementAlgebra.operation(accumulator, getByOffset(index)) - return accumulator - } - - public inline fun Buffer.foldWithLabel(initial: R, operation: A.(acc: R, arg: T, label: L) -> R): R { - val labels = labels - var accumulator = initial - for (index in this.offsetIndices) accumulator = - elementAlgebra.operation(accumulator, getByOffset(index), labels[index]) - return accumulator - } - - /** - * Zip two buffers in the range whe they overlap - */ - public inline fun Buffer.zip( - other: Buffer, - crossinline operation: A.(left: T, right: T) -> T, - ): Series { - val newRange = offsetIndices.intersect(other.offsetIndices) - return seriesByOffset(startOffset = newRange.first, size = newRange.last + 1 - newRange.first) { offset -> - elementAlgebra.operation( - getByOffset(offset), - other.getByOffset(offset) - ) - } - } - - /** - * Zip buffer with itself, but shifted - * */ - public inline fun Buffer.zipWithShift( - shift: Int = 1, - crossinline operation: A.(left: T, right: T) -> T - ): Buffer { - val shifted = this.moveBy(shift) - return zip(shifted, operation) - } - - override fun Buffer.unaryMinus(): Buffer = map { -it } - - override fun add(left: Buffer, right: Buffer): Series = left.zip(right) { l, r -> l + r } - - override fun multiply(left: Buffer, right: Buffer): Buffer = left.zip(right) { l, r -> l * r } - - public fun Buffer.difference(shift: Int=1): Buffer = this.zipWithShift(shift) {l, r -> r - l} - - public companion object -} - -public fun , BA : BufferAlgebra, L> BA.seriesAlgebra(labels: Iterable): SeriesAlgebra { - val l = labels.toList() - return SeriesAlgebra(this) { - if (it in l.indices) l[it] else error("Index $it is outside of labels range ${l.indices}") - } -} - -public fun , BA : BufferAlgebra, L> BA.seriesAlgebra(labelGenerator: (Int) -> L): SeriesAlgebra = - SeriesAlgebra(this, labelGenerator) - -/** - * Create a series algebra using offset as a label - */ -public fun , BA : BufferAlgebra> BA.seriesAlgebra(): SeriesAlgebra = - SeriesAlgebra(this) { it } \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt deleted file mode 100644 index 4becb3413..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.series - -import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.operations.DoubleField.pow -import space.kscience.kmath.operations.fold -import kotlin.math.absoluteValue - - -/** - * Container class for Variance Ratio Test result: - * ratio itself, corresponding Z-score, also it's p-value - */ -public data class VarianceRatioTestResult( - val varianceRatio: Double = 1.0, - val zScore: Double = 0.0, - val pValue: Double = 0.5, -) - - -/** - * Calculates the Z-statistic and the p-value for the Lo and MacKinlay's Variance Ratio test (1987) - * under Homoscedastic or Heteroscedstic assumptions - * with two-sided p-value test - * https://ssrn.com/abstract=346975 - * - * @author https://github.com/mrFendel - */ -public fun SeriesAlgebra.varianceRatioTest( - series: Series, - shift: Int, - homoscedastic: Boolean = true, -): VarianceRatioTestResult { - - require(shift > 1) { "Shift must be greater than one" } - require(shift < series.size) { "Shift must be smaller than sample size" } - val sum = { x: Double, y: Double -> x + y } - - - val mean = series.fold(0.0, sum) / series.size - val demeanedSquares = series.map { (it - mean).pow(2) } - val variance = demeanedSquares.fold(0.0, sum) - if (variance == 0.0) return VarianceRatioTestResult() - - - var seriesAgg = series - for (i in 1.. v1 + v2 } - } - - val demeanedSquaresAgg = seriesAgg.map { (it - shift * mean).pow(2) } - val varianceAgg = demeanedSquaresAgg.fold(0.0, sum) - - val varianceRatio = - varianceAgg * (series.size.toDouble() - 1) / variance / (series.size.toDouble() - shift.toDouble() + 1) / (1 - shift.toDouble() / series.size.toDouble()) / shift.toDouble() - - - // calculating asymptotic variance - val phi = if (homoscedastic) { // under homoscedastic null hypothesis - 2 * (2 * shift - 1.0) * (shift - 1.0) / (3 * shift * series.size) - } else { // under heteroscedastic null hypothesis - var accumulator = 0.0 - for (j in 1.. v1 * v2 }.fold(0.0, sum) / variance.pow(2) - accumulator += delta * 4 * (shift - j).toDouble().pow(2) / shift.toDouble().pow(2) - } - accumulator - } - - val zScore = (varianceRatio - 1) / phi.pow(0.5) - val pValue = 2 * (1 - NormalDistribution.zSNormalCDF(zScore.absoluteValue)) - return VarianceRatioTestResult(varianceRatio, zScore, pValue) -} - - - - diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt deleted file mode 100644 index dc21fe6d9..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.series - -import space.kscience.kmath.operations.BufferAlgebra -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.sumWithGroupOf - -public fun , BA : BufferAlgebra, L : Comparable> MonotonicSeriesAlgebra.import( - data: List>, -): Series { - val groupedData: Map>> = data.groupBy { floorOffset(it.first) } - val minIndex = groupedData.minOf { it.key } - val maxIndex = groupedData.maxOf { it.key } - return elementAlgebra.bufferFactory(maxIndex - minIndex) { relativeIndex -> - val index = relativeIndex + minIndex - groupedData[index]?.sumWithGroupOf(elementAlgebra) { it.second } ?: elementAlgebra.zero - }.moveTo(minIndex) -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt deleted file mode 100644 index fa5e0addd..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt +++ /dev/null @@ -1,97 +0,0 @@ -package space.kscience.kmath.series - -import space.kscience.kmath.operations.BufferAlgebra -import space.kscience.kmath.operations.ExponentialOperations -import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.TrigonometricOperations -import space.kscience.kmath.structures.Buffer - - -//trigonometric - -public fun SeriesAlgebra.sin( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.sin(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.cos( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.cos(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.tan( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.tan(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.asin( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.asin(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.acos( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.acos(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.atan( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : TrigonometricOperations> = - bufferAlgebra.atan(arg).moveTo(arg.startOffset) - - -//exponential - -public fun SeriesAlgebra.exp( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.exp(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.ln( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.ln(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.sinh( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.sinh(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.cosh( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.cosh(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.tanh( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.tanh(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.asinh( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.asinh(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.acosh( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.acosh(arg).moveTo(arg.startOffset) - -public fun SeriesAlgebra.atanh( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : ExponentialOperations> = - bufferAlgebra.atanh(arg).moveTo(arg.startOffset) - - -//power - -public fun SeriesAlgebra.power( - arg: Buffer, - pow: Number, -): Series where BA : BufferAlgebra, BA : PowerOperations> = - bufferAlgebra.power(arg, pow).moveTo(arg.startOffset) - -public fun SeriesAlgebra.sqrt( - arg: Buffer, -): Series where BA : BufferAlgebra, BA : PowerOperations> = - bufferAlgebra.sqrt(arg).moveTo(arg.startOffset) \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/MCScope.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt similarity index 75% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/MCScope.kt rename to kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt index 2049a84fc..9e5c70a26 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/MCScope.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt @@ -1,13 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.random +package space.kscience.kmath.stat import kotlinx.coroutines.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.coroutineContext @@ -22,25 +20,17 @@ public class MCScope( public val random: RandomGenerator, ) -public fun MCScope.asCoroutineScope(): CoroutineScope = object : CoroutineScope { - override val coroutineContext: CoroutineContext get() = this@asCoroutineScope.coroutineContext -} - /** * Launches a supervised Monte-Carlo scope */ -public suspend inline fun mcScope(generator: RandomGenerator, block: MCScope.() -> T): T { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return MCScope(coroutineContext, generator).block() -} +public suspend inline fun mcScope(generator: RandomGenerator, block: MCScope.() -> T): T = + MCScope(coroutineContext, generator).block() /** * Launch mc scope with a given seed */ -public suspend inline fun mcScope(seed: Long, block: MCScope.() -> T): T { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return mcScope(RandomGenerator.default(seed), block) -} +public suspend inline fun mcScope(seed: Long, block: MCScope.() -> T): T = + mcScope(RandomGenerator.default(seed), block) /** * Specialized launch for [MCScope]. Behaves the same way as regular [CoroutineScope.launch], but also stores the generator fork. diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt index 3bf8b33e8..9769146fb 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -27,41 +27,24 @@ public class Mean( override suspend fun evaluate(data: Buffer): T = super.evaluate(data) - override suspend fun computeIntermediate(data: Buffer): Pair = group { - var res = zero - for (i in data.indices) { - res += data[i] - } - res to data.size - } + public override suspend fun computeIntermediate(data: Buffer): Pair = + evaluateBlocking(data) to data.size - override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = + public override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = group { first.first + second.first } to (first.second + second.second) - override suspend fun toResult(intermediate: Pair): T = group { + public override suspend fun toResult(intermediate: Pair): T = group { division(intermediate.first, intermediate.second) } public companion object { - @Deprecated("Use Double.mean instead") + //TODO replace with optimized version which respects overflow public val double: Mean = Mean(DoubleField) { sum, count -> sum / count } - - @Deprecated("Use Int.mean instead") public val int: Mean = Mean(IntRing) { sum, count -> sum / count } - - @Deprecated("Use Long.mean instead") public val long: Mean = Mean(LongRing) { sum, count -> sum / count } - public fun evaluate(buffer: Buffer): Double = DoubleField.mean.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Int = IntRing.mean.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Long = LongRing.mean.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Double = double.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Int = int.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Long = long.evaluateBlocking(buffer) } -} - - -//TODO replace with optimized version which respects overflow -public val DoubleField.mean: Mean get() = Mean(DoubleField) { sum, count -> sum / count } -public val IntRing.mean: Mean get() = Mean(IntRing) { sum, count -> sum / count } -public val LongRing.mean: Mean get() = Mean(LongRing) { sum, count -> sum / count } - - +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt index 87046cd46..70754eab7 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt @@ -1,18 +1,18 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.stat -import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asSequence /** * Non-composable median */ public class Median(private val comparator: Comparator) : BlockingStatistic { - override fun evaluateBlocking(data: Buffer): T = + public override fun evaluateBlocking(data: Buffer): T = data.asSequence().sortedWith(comparator).toList()[data.size / 2] //TODO check if this is correct public companion object { diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomChain.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt similarity index 87% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomChain.kt rename to kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt index 7e0ee3cd4..5041e7359 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomChain.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.random +package space.kscience.kmath.stat import space.kscience.kmath.chains.BlockingDoubleChain import space.kscience.kmath.chains.Chain @@ -31,7 +31,7 @@ public fun RandomGenerator.chain(generator: suspend RandomGenerator.() -> R) * A type-specific double chunk random chain */ public class UniformDoubleChain(public val generator: RandomGenerator) : BlockingDoubleChain { - override fun nextBufferBlocking(size: Int): DoubleBuffer = generator.nextDoubleBuffer(size) + public override fun nextBufferBlocking(size: Int): DoubleBuffer = generator.nextDoubleBuffer(size) override suspend fun nextBuffer(size: Int): DoubleBuffer = nextBufferBlocking(size) override suspend fun fork(): UniformDoubleChain = UniformDoubleChain(generator.fork()) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt similarity index 75% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomGenerator.kt rename to kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt index f7388006e..3ff12f383 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomGenerator.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.random +package space.kscience.kmath.stat import space.kscience.kmath.structures.DoubleBuffer import kotlin.random.Random @@ -23,7 +23,7 @@ public interface RandomGenerator { public fun nextDouble(): Double /** - * A chunk of doubles of given [size]. + * A chunk of doubles of given [size] */ public fun nextDoubleBuffer(size: Int): DoubleBuffer = DoubleBuffer(size) { nextDouble() } @@ -57,7 +57,7 @@ public interface RandomGenerator { public fun nextLong(until: Long): Long /** - * Fills a subrange with the specified byte [array] starting from [fromIndex] inclusive and ending [toIndex] exclusive + * Fills a subrange of the specified byte [array] starting from [fromIndex] inclusive and ending [toIndex] exclusive * with random bytes. * * @return [array] with the subrange filled with random bytes. @@ -70,7 +70,7 @@ public interface RandomGenerator { public fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) } /** - * Create a new generator that is independent of current generator (operations on new generator do not affect this one + * Create a new generator which is independent from current generator (operations on new generator do not affect this one * and vise versa). The statistical properties of new generator should be the same as for this one. * For pseudo-random generator, the fork is keeping the same sequence of numbers for given call order for each run. * @@ -97,17 +97,17 @@ public interface RandomGenerator { * @property random the underlying [Random] object. */ public class DefaultGenerator(public val random: Random = Random) : RandomGenerator { - override fun nextBoolean(): Boolean = random.nextBoolean() - override fun nextDouble(): Double = random.nextDouble() - override fun nextInt(): Int = random.nextInt() - override fun nextInt(until: Int): Int = random.nextInt(until) - override fun nextLong(): Long = random.nextLong() - override fun nextLong(until: Long): Long = random.nextLong(until) + public override fun nextBoolean(): Boolean = random.nextBoolean() + public override fun nextDouble(): Double = random.nextDouble() + public override fun nextInt(): Int = random.nextInt() + public override fun nextInt(until: Int): Int = random.nextInt(until) + public override fun nextLong(): Long = random.nextLong() + public override fun nextLong(until: Long): Long = random.nextLong(until) - override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { + public override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { random.nextBytes(array, fromIndex, toIndex) } - override fun nextBytes(size: Int): ByteArray = random.nextBytes(size) - override fun fork(): RandomGenerator = RandomGenerator.default(random.nextLong()) + public override fun nextBytes(size: Int): ByteArray = random.nextBytes(size) + public override fun fork(): RandomGenerator = RandomGenerator.default(random.nextLong()) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Rank.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Rank.kt deleted file mode 100644 index 5a873b466..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Rank.kt +++ /dev/null @@ -1,35 +0,0 @@ -package space.kscience.kmath.stat - -import space.kscience.kmath.operations.asIterable -import space.kscience.kmath.structures.Buffer - -/** - * Rank statistics - */ -public class Rank> : BlockingStatistic { - override fun evaluateBlocking(data: Buffer): IntArray = Companion.evaluate(data) - - public companion object { - public fun > evaluate(data: Buffer): IntArray { - // https://www.geeksforgeeks.org/rank-elements-array/ - val permutations = ArrayList>(data.size) - data.asIterable().mapIndexedTo(permutations) { i, v -> v to i } - permutations.sortBy { it.first } - var rank = 1 - var i = 0 - val r = IntArray(data.size) - while (i < data.size) { - var j = i - while (j < data.size - 1 && permutations[j].first == permutations[j + 1]) ++j - val n = j - i + 1 - (0 until n).map { k -> - val idx = permutations[i + k].second - r[idx] = rank + ((n - 1) * 0.5f).toInt() - } - rank += n - i += n - } - return r - } - } -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt similarity index 66% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt rename to kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index b87a429df..51ae78d3d 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -1,23 +1,18 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.stat import kotlinx.coroutines.flow.first -import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.combine -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.IntBuffer +import space.kscience.kmath.chains.collect +import space.kscience.kmath.structures.* import kotlin.jvm.JvmName /** - * Sampler that generates chains of values of type [T]. + * Sampler that generates chains of values of type [T] in a chain of type [C]. */ public fun interface Sampler { /** @@ -32,17 +27,16 @@ public fun interface Sampler { /** * Sample a bunch of values */ -@OptIn(UnstableKMathAPI::class) public fun Sampler.sampleBuffer( generator: RandomGenerator, size: Int, - bufferFactory: BufferFactory = BufferFactory.boxing(), + bufferFactory: BufferFactory = Buffer.Companion::boxing, ): Chain> { require(size > 1) //creating temporary storage once val tmp = ArrayList(size) - return sample(generator).combine { chain -> + return sample(generator).collect { chain -> //clear list from previous run tmp.clear() //Fill list @@ -70,12 +64,3 @@ public fun Sampler.sampleBuffer(generator: RandomGenerator, size: Int): @JvmName("sampleIntBuffer") public fun Sampler.sampleBuffer(generator: RandomGenerator, size: Int): Chain> = sampleBuffer(generator, size, ::IntBuffer) - - -/** - * Samples a [Buffer] of values from this [Sampler]. - */ -public suspend fun Sampler.nextBuffer(generator: RandomGenerator, size: Int): Buffer = - sampleBuffer(generator, size).first() - -//TODO add `context(RandomGenerator) Sampler.nextBuffer \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt new file mode 100644 index 000000000..b3d607ab0 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.stat + +import space.kscience.kmath.chains.Chain +import space.kscience.kmath.chains.ConstantChain +import space.kscience.kmath.chains.map +import space.kscience.kmath.chains.zip +import space.kscience.kmath.operations.Group +import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.operations.invoke + +/** + * Implements [Sampler] by sampling only certain [value]. + * + * @property value the value to sample. + */ +public class ConstantSampler(public val value: T) : Sampler { + public override fun sample(generator: RandomGenerator): Chain = ConstantChain(value) +} + +/** + * Implements [Sampler] by delegating sampling to value of [chainBuilder]. + * + * @property chainBuilder the provider of [Chain]. + */ +public class BasicSampler(public val chainBuilder: (RandomGenerator) -> Chain) : Sampler { + public override fun sample(generator: RandomGenerator): Chain = chainBuilder(generator) +} + +/** + * A space of samplers. Allows to perform simple operations on distributions. + * + * @property algebra the space to provide addition and scalar multiplication for [T]. + */ +public class SamplerSpace(public val algebra: S) : Group>, + ScaleOperations> where S : Group, S : ScaleOperations { + + public override val zero: Sampler = ConstantSampler(algebra.zero) + + public override fun add(a: Sampler, b: Sampler): Sampler = BasicSampler { generator -> + a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } } + } + + public override fun scale(a: Sampler, value: Double): Sampler = BasicSampler { generator -> + a.sample(generator).map { a -> + algebra { a * value } + } + } + + public override fun Sampler.unaryMinus(): Sampler = scale(this, -1.0) +} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt index d7638ff81..1b05aa9cd 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -8,6 +8,7 @@ package space.kscience.kmath.stat import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.runningReduce @@ -17,31 +18,23 @@ import space.kscience.kmath.structures.Buffer /** * A function, that transforms a buffer of random quantities to some resulting value */ -public fun interface Statistic { +public interface Statistic { public suspend fun evaluate(data: Buffer): R } -public suspend operator fun Statistic.invoke(data: Buffer): R = evaluate(data) - -/** - * A statistic that is computed in a synchronous blocking mode - */ -public fun interface BlockingStatistic : Statistic { +public interface BlockingStatistic: Statistic{ public fun evaluateBlocking(data: Buffer): R - override suspend fun evaluate(data: Buffer): R = evaluateBlocking(data) + override suspend fun evaluate(data: Buffer): R = evaluateBlocking(data) } -public operator fun BlockingStatistic.invoke(data: Buffer): R = evaluateBlocking(data) - /** * A statistic tha could be computed separately on different blocks of data and then composed - * - * @param T the source type. - * @param I the intermediate block type. - * @param R the result type. + * @param T - source type + * @param I - intermediate block type + * @param R - result type */ -public interface ComposableStatistic : Statistic { +public interface ComposableStatistic : Statistic { //compute statistic on a single block public suspend fun computeIntermediate(data: Buffer): I @@ -51,13 +44,11 @@ public interface ComposableStatistic : Statistic { //Transform block to result public suspend fun toResult(intermediate: I): R - override suspend fun evaluate(data: Buffer): R = toResult(computeIntermediate(data)) + public override suspend fun evaluate(data: Buffer): R = toResult(computeIntermediate(data)) } -/** - * Flow intermediate state of the [ComposableStatistic] - */ -@OptIn(ExperimentalCoroutinesApi::class) +@FlowPreview +@ExperimentalCoroutinesApi private fun ComposableStatistic.flowIntermediate( flow: Flow>, dispatcher: CoroutineDispatcher = Dispatchers.Default, @@ -72,7 +63,7 @@ private fun ComposableStatistic.flowIntermediate( * * The resulting flow contains values that include the whole previous statistics, not only the last chunk. */ -@OptIn(ExperimentalCoroutinesApi::class) +@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) public fun ComposableStatistic.flow( flow: Flow>, dispatcher: CoroutineDispatcher = Dispatchers.Default, diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt deleted file mode 100644 index cce61519b..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt +++ /dev/null @@ -1,67 +0,0 @@ -package space.kscience.kmath.stat - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.misc.sorted -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBufferFactory - -public interface StatisticalAlgebra, out BA : BufferAlgebra> : Algebra> { - public val bufferAlgebra: BA - public val elementAlgebra: A get() = bufferAlgebra.elementAlgebra - override val bufferFactory: MutableBufferFactory> get() = bufferAlgebra.bufferFactory -} - -/** - * Compute [empirical CDF function](https://en.wikipedia.org/wiki/Empirical_distribution_function) - */ -public fun > StatisticalAlgebra.ecdf(buffer: Buffer): (T) -> Double = { arg -> - buffer.asIterable().count { it < arg }.toDouble() / buffer.size -} - -/** - * Resulting value of kolmogorov-smirnov two-sample statistic - */ -@UnstableKMathAPI -public data class KMComparisonResult>(val n: Int, val m: Int, val value: T) - -/** - * Kolmogorov-Smirnov sample comparison test - * Implementation copied from https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/index.html?org/apache/commons/math3/stat/inference/KolmogorovSmirnovTest.html - */ -@UnstableKMathAPI -public fun , A, BA : BufferAlgebra> StatisticalAlgebra.ksComparisonStatistic( - x: Buffer, - y: Buffer, -): KMComparisonResult where A : Group, A : NumericAlgebra = with(elementAlgebra) { - // Copy and sort the sample arrays - val sx = x.sorted() - val sy = y.sorted() - val n = sx.size - val m = sy.size - - var rankX: Int = 0 - var rankY: Int = 0 - var curD: T = zero - - // Find the max difference between cdf_x and cdf_y - var supD: T = zero - do { - val z = if (sx[rankX] <= sy[rankY]) sx[rankX] else sy[rankY] - while (rankX < n && sx[rankX].compareTo(z) == 0) { - rankX += 1 - curD += number(m) - } - - while (rankY < m && sy[rankY].compareTo(z) == 0) { - rankY += 1 - curD -= number(n) - } - - when { - curD > supD -> supD = curD - -curD > supD -> supD = -curD - } - } while (rankX < n && rankY < m) - return KMComparisonResult(n, m, supD) -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt similarity index 78% rename from kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt rename to kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt index 953be06fd..970a3aab5 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt @@ -1,15 +1,16 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.distributions +package space.kscience.kmath.stat import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.SimpleChain -import space.kscience.kmath.random.RandomGenerator +import space.kscience.kmath.distributions.Distribution +import space.kscience.kmath.distributions.UnivariateDistribution -public class UniformDistribution(public val range: ClosedFloatingPointRange) : Distribution1D { +public class UniformDistribution(public val range: ClosedFloatingPointRange) : UnivariateDistribution { private val length: Double = range.endInclusive - range.start override fun probability(arg: Double): Double = if (arg in range) 1.0 / length else 0.0 diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt deleted file mode 100644 index 38cd5f900..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.stat - -import space.kscience.kmath.operations.Field -import kotlin.math.pow -import kotlin.math.sqrt - -/** - * A combination of a random [value] and its [dispersion]. - * - * [dispersion] must be positive. - */ -public data class ValueAndError(val value: Double, val dispersion: Double) { - init { - require(dispersion >= 0) { "Dispersion must be non-negative" } - } - - val error: Double get() = sqrt(dispersion) -} - -/** - * An algebra for double value + its error combination. The multiplication assumes linear error propagation - */ -public object ValueAndErrorField : Field { - - override val zero: ValueAndError = ValueAndError(0.0, 0.0) - - override val one: ValueAndError = ValueAndError(1.0, 0.0) - - override fun add(left: ValueAndError, right: ValueAndError): ValueAndError = - ValueAndError(left.value + right.value, left.dispersion + right.dispersion) - - override fun ValueAndError.unaryMinus(): ValueAndError = - ValueAndError(-value, dispersion) - - //TODO study performance impact of pow(2). On JVM it does not exist: https://stackoverflow.com/questions/29144275/xx-vs-math-powx-2-java-performance - - override fun multiply(left: ValueAndError, right: ValueAndError): ValueAndError { - val value = left.value * right.value - val dispersion = (left.dispersion / left.value.pow(2) + right.dispersion / right.value.pow(2)) * value.pow(2) - return ValueAndError(value, dispersion) - } - - override fun divide(left: ValueAndError, right: ValueAndError): ValueAndError { - val value = left.value / right.value - val dispersion = (left.dispersion / left.value.pow(2) + right.dispersion / right.value.pow(2)) * value.pow(2) - return ValueAndError(value, dispersion) - } - - override fun scale(a: ValueAndError, value: Double): ValueAndError = - ValueAndError(a.value * value, a.dispersion * value.pow(2)) -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt deleted file mode 100644 index ca9755ad5..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.stat - -import space.kscience.kmath.expressions.AutoDiffProcessor -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.ExpressionAlgebra -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.asIterable -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices -import kotlin.jvm.JvmName - -//TODO move to stat - -/** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic - * differentiation. - * - * **WARNING** All elements of [yErr] must be positive. - */ -@JvmName("genericChiSquaredExpression") -public fun , I : Any, A> AutoDiffProcessor.chiSquaredExpression( - x: Buffer, - y: Buffer, - yErr: Buffer, - model: A.(I) -> I, -): DifferentiableExpression where A : ExtendedField, A : ExpressionAlgebra { - require(x.size == y.size) { "X and y buffers should be of the same size" } - require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } - - return differentiate { - var sum = zero - - x.indices.forEach { - val xValue = const(x[it]) - val yValue = const(y[it]) - val yErrValue = const(yErr[it]) - val modelValue = model(xValue) - sum += ((yValue - modelValue) / yErrValue).pow(2) - } - - sum - } -} - -public fun AutoDiffProcessor.chiSquaredExpression( - x: Buffer, - y: Buffer, - yErr: Buffer, - model: A.(I) -> I, -): DifferentiableExpression where A : ExtendedField, A : ExpressionAlgebra { - require(yErr.asIterable().all { it > 0.0 }) { "All errors must be strictly positive" } - return chiSquaredExpression(x, y, yErr, model) -} \ No newline at end of file diff --git a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt deleted file mode 100644 index d83abb3f4..000000000 --- a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.series - -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.bufferAlgebra -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.slice -import kotlin.math.PI -import kotlin.test.Test -import kotlin.test.assertEquals - -class TestSeries { - - @Test - fun zip() = with(Double.algebra.bufferAlgebra.seriesAlgebra()){ - val s1 = series(100) { sin(2 * PI * it / 100) + 1.0 } - - val s2 = s1.slice(20..50).moveTo(40) - - val s3: Buffer = s1.zip(s2) { l, r -> l + r } //s1 + s2 - - assertEquals(s3.getByOffset(40),s1.getByOffset(40) + s1.getByOffset(20)) - } -} \ No newline at end of file diff --git a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestVarianceRatioTest.kt b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestVarianceRatioTest.kt deleted file mode 100644 index afc0d541d..000000000 --- a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestVarianceRatioTest.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018-2023 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.series - -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.bufferAlgebra -import kotlin.math.PI -import kotlin.test.Test -import kotlin.test.assertEquals - -class TestVarianceRatioTest { - - @Test - fun monotonicData() { - with(Double.algebra.bufferAlgebra.seriesAlgebra()) { - val monotonicData = series(10) { it * 1.0 } - val resultHomo = varianceRatioTest(monotonicData, 2, homoscedastic = true) - assertEquals(1.818181, resultHomo.varianceRatio, 1e-6) - // homoscedastic zScore - assertEquals(2.587318, resultHomo.zScore, 1e-6) - assertEquals(.0096, resultHomo.pValue, 1e-4) - val resultHetero = varianceRatioTest(monotonicData, 2, homoscedastic = false) - // heteroscedastic zScore - assertEquals(0.819424, resultHetero.zScore, 1e-6) - assertEquals(.4125, resultHetero.pValue, 1e-4) - } - } - - @Test - fun volatileData() { - with(Double.algebra.bufferAlgebra.seriesAlgebra()) { - val volatileData = series(10) { sin(PI * it + PI/2) + 1.0} - val resultHomo = varianceRatioTest(volatileData, 2) - assertEquals(0.0, resultHomo.varianceRatio, 1e-6) - // homoscedastic zScore - assertEquals(-3.162277, resultHomo.zScore, 1e-6) - assertEquals(.0015, resultHomo.pValue, 1e-4) - val resultHetero = varianceRatioTest(volatileData, 2, homoscedastic = false) - // heteroscedastic zScore - assertEquals(-1.0540925, resultHetero.zScore, 1e-6) - assertEquals(.2918, resultHetero.pValue, 1e-4) - } - } - - @Test - fun negativeData() { - with(Double.algebra.bufferAlgebra.seriesAlgebra()) { - val negativeData = series(10) { sin(it * 1.2)} - val resultHomo = varianceRatioTest(negativeData, 3) - assertEquals(1.240031, resultHomo.varianceRatio, 1e-6) - // homoscedastic zScore - assertEquals(0.509183, resultHomo.zScore, 1e-6) - val resultHetero = varianceRatioTest(negativeData, 3, homoscedastic = false) - // heteroscedastic zScore - assertEquals(0.209202, resultHetero.zScore, 1e-6) - } - } - - @Test - fun zeroVolatility() { - with(Double.algebra.bufferAlgebra.seriesAlgebra()) { - val zeroVolData = series(10) { 0.0 } - val result = varianceRatioTest(zeroVolData, 4) - assertEquals(1.0, result.varianceRatio, 1e-6) - assertEquals(0.0, result.zScore, 1e-6) - assertEquals(0.5, result.pValue, 1e-4) - } - } -} \ No newline at end of file diff --git a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt index 2c6391612..1ff6481ac 100644 --- a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt +++ b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,33 +7,29 @@ package space.kscience.kmath.stat import org.apache.commons.rng.UniformRandomProvider import org.apache.commons.rng.simple.RandomSource -import space.kscience.kmath.random.RandomGenerator /** * Implements [RandomGenerator] by delegating all operations to [RandomSource]. * * @property source the underlying [RandomSource] object. */ -public class RandomSourceGenerator internal constructor( - public val source: RandomSource, - seed: Long?, -) : RandomGenerator { +public class RandomSourceGenerator internal constructor(public val source: RandomSource, seed: Long?) : RandomGenerator { internal val random: UniformRandomProvider = seed?.let { RandomSource.create(source, seed) } ?: RandomSource.create(source) - override fun nextBoolean(): Boolean = random.nextBoolean() - override fun nextDouble(): Double = random.nextDouble() - override fun nextInt(): Int = random.nextInt() - override fun nextInt(until: Int): Int = random.nextInt(until) - override fun nextLong(): Long = random.nextLong() - override fun nextLong(until: Long): Long = random.nextLong(until) + public override fun nextBoolean(): Boolean = random.nextBoolean() + public override fun nextDouble(): Double = random.nextDouble() + public override fun nextInt(): Int = random.nextInt() + public override fun nextInt(until: Int): Int = random.nextInt(until) + public override fun nextLong(): Long = random.nextLong() + public override fun nextLong(until: Long): Long = random.nextLong(until) - override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { + public override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { require(toIndex > fromIndex) random.nextBytes(array, fromIndex, toIndex - fromIndex) } - override fun fork(): RandomGenerator = RandomSourceGenerator(source, nextLong()) + public override fun fork(): RandomGenerator = RandomSourceGenerator(source, nextLong()) } /** @@ -47,23 +43,23 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * * @return the next random value. */ - override fun nextBoolean(): Boolean = generator.nextBoolean() + public override fun nextBoolean(): Boolean = generator.nextBoolean() /** * Generates a [Float] value between 0 and 1. * * @return the next random value between 0 and 1. */ - override fun nextFloat(): Float = generator.nextDouble().toFloat() + public override fun nextFloat(): Float = generator.nextDouble().toFloat() /** * Generates [Byte] values and places them into a user-supplied array. * - * The number of random bytes produced is equal to the length of the byte array. + * The number of random bytes produced is equal to the length of the the byte array. * * @param bytes byte array in which to put the random bytes. */ - override fun nextBytes(bytes: ByteArray): Unit = generator.fillBytes(bytes) + public override fun nextBytes(bytes: ByteArray): Unit = generator.fillBytes(bytes) /** * Generates [Byte] values and places them into a user-supplied array. @@ -75,7 +71,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * @param start the index at which to start inserting the generated bytes. * @param len the number of bytes to insert. */ - override fun nextBytes(bytes: ByteArray, start: Int, len: Int) { + public override fun nextBytes(bytes: ByteArray, start: Int, len: Int) { generator.fillBytes(bytes, start, start + len) } @@ -84,7 +80,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * * @return the next random value. */ - override fun nextInt(): Int = generator.nextInt() + public override fun nextInt(): Int = generator.nextInt() /** * Generates an [Int] value between 0 (inclusive) and the specified value (exclusive). @@ -92,21 +88,21 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * @param n the bound on the random number to be returned. Must be positive. * @return a random integer between 0 (inclusive) and [n] (exclusive). */ - override fun nextInt(n: Int): Int = generator.nextInt(n) + public override fun nextInt(n: Int): Int = generator.nextInt(n) /** * Generates a [Double] value between 0 and 1. * * @return the next random value between 0 and 1. */ - override fun nextDouble(): Double = generator.nextDouble() + public override fun nextDouble(): Double = generator.nextDouble() /** * Generates a [Long] value. * * @return the next random value. */ - override fun nextLong(): Long = generator.nextLong() + public override fun nextLong(): Long = generator.nextLong() /** * Generates a [Long] value between 0 (inclusive) and the specified value (exclusive). @@ -114,7 +110,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * @param n Bound on the random number to be returned. Must be positive. * @return a random long value between 0 (inclusive) and [n] (exclusive). */ - override fun nextLong(n: Long): Long = generator.nextLong(n) + public override fun nextLong(n: Long): Long = generator.nextLong(n) } /** diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt index b9b9dadba..066fd69e6 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt @@ -1,19 +1,19 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.stat -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test -import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.samplers.GaussianSampler internal class CommonsDistributionsTest { @Test - fun testNormalDistributionSuspend() = runBlocking { + fun testNormalDistributionSuspend() = GlobalScope.launch { val distribution = GaussianSampler(7.0, 2.0) val generator = RandomGenerator.default(1) val sample = distribution.sample(generator).nextBuffer(1000) diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt index dbcf32e27..075d7f3e5 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt @@ -1,27 +1,25 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.stat import kotlinx.coroutines.* -import space.kscience.kmath.random.launch -import space.kscience.kmath.random.mcScope import java.util.* import kotlin.test.Test import kotlin.test.assertEquals data class RandomResult(val branch: String, val order: Int, val value: Int) -internal typealias ATest = suspend () -> Set +typealias ATest = suspend CoroutineScope.() -> Set -internal class MCScopeTest { +class MCScopeTest { val simpleTest: ATest = { mcScope(1111) { val res = Collections.synchronizedSet(HashSet()) - launch{ + launch { //println(random) repeat(10) { delay(10) @@ -68,7 +66,7 @@ internal class MCScopeTest { } - @OptIn(DelicateCoroutinesApi::class) + @OptIn(ObsoleteCoroutinesApi::class) fun compareResult(test: ATest) { val res1 = runBlocking(Dispatchers.Default) { test() } val res2 = runBlocking(newSingleThreadContext("test")) { test() } diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt index 0076006e6..1dbbf591b 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt @@ -1,13 +1,11 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.stat import kotlinx.coroutines.runBlocking -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.random.chain import kotlin.test.Test class SamplerTest { diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt index 3be7fa314..1dd5c5161 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt @@ -1,20 +1,15 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.stat +import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.last -import kotlinx.coroutines.flow.take import kotlinx.coroutines.runBlocking -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.random.chain import space.kscience.kmath.streaming.chunked import kotlin.test.Test -import kotlin.test.assertEquals internal class StatisticTest { //create a random number generator. @@ -27,27 +22,12 @@ internal class StatisticTest { val chunked = data.chunked(1000) @Test - fun singleBlockingMean() { - val first = runBlocking { chunked.first() } - val res = DoubleField.mean(first) - assertEquals(0.5, res, 1e-1) + fun testParallelMean() = runBlocking { + val average = Mean.double + .flow(chunked) //create a flow with results + .drop(99) // Skip first 99 values and use one with total data + .first() //get 1e5 data samples average + + println(average) } - - @Test - fun singleSuspendMean() = runBlocking { - val first = runBlocking { chunked.first() } - val res = DoubleField.mean(first) - assertEquals(0.5, res, 1e-1) - } - - @Test - fun parallelMean() = runBlocking { - val average = DoubleField.mean - .flow(chunked) //create a flow from evaluated results - .take(100) // Take 100 data chunks from the source and accumulate them - .last() //get 1e5 data samples average - - assertEquals(0.5, average, 1e-2) - } - } diff --git a/kmath-symja/README.md b/kmath-symja/README.md deleted file mode 100644 index 8672c6a71..000000000 --- a/kmath-symja/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-symja - -Symja integration module - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-symja:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-symja:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-symja:0.4.0-dev-1") -} -``` diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts deleted file mode 100644 index 8741de2ae..000000000 --- a/kmath-symja/build.gradle.kts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -plugins { - id("space.kscience.gradle.jvm") -} - -description = "Symja integration module" - -dependencies { - api("org.matheclipse:matheclipse-core:2.0.0-SNAPSHOT") { - // Incorrect transitive dependencies - exclude("org.apfloat", "apfloat") - exclude("org.hipparchus", "hipparchus-clustering") - exclude("org.hipparchus", "hipparchus-core") - exclude("org.hipparchus", "hipparchus-fft") - exclude("org.hipparchus", "hipparchus-fitting") - exclude("org.hipparchus", "hipparchus-ode") - exclude("org.hipparchus", "hipparchus-optim") - exclude("org.hipparchus", "hipparchus-stat") - } - - // Replaces for incorrect transitive dependencies - api("org.apfloat:apfloat:1.10.0") - api("org.hipparchus:hipparchus-clustering:1.8") - api("org.hipparchus:hipparchus-core:1.8") - api("org.hipparchus:hipparchus-fft:1.8") - api("org.hipparchus:hipparchus-fitting:1.8") - api("org.hipparchus:hipparchus-ode:1.8") - api("org.hipparchus:hipparchus-optim:1.8") - api("org.hipparchus:hipparchus-stat:1.8") - - api(project(":kmath-core")) - testImplementation("org.slf4j:slf4j-simple:1.7.31") -} - -readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE -} diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt deleted file mode 100644 index 0f8014913..000000000 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.symja - -import org.matheclipse.core.eval.ExprEvaluator -import org.matheclipse.core.expression.F -import space.kscience.kmath.expressions.SpecialDifferentiableExpression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.interpret -import space.kscience.kmath.operations.NumericAlgebra - -/** - * Represents [MST] based [space.kscience.kmath.expressions.DifferentiableExpression] relying on - * [Symja](https://github.com/axkr/symja_android_library). - * - * The principle of this API is converting the [mst] to an [org.matheclipse.core.interfaces.IExpr], differentiating it - * with Symja's [F.D], then converting [org.matheclipse.core.interfaces.IExpr] back to [MST]. - * - * @param T The type of number. - * @param A The [NumericAlgebra] of [T]. - * @property algebra The [A] instance. - * @property mst The [MST] node. - */ -public class SymjaExpression>( - public val algebra: A, - public val mst: MST, - public val evaluator: ExprEvaluator = DEFAULT_EVALUATOR, -) : SpecialDifferentiableExpression> { - override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) - - override fun derivativeOrNull(symbols: List): SymjaExpression = SymjaExpression( - algebra, - symbols.map(Symbol::toIExpr).fold(mst.toIExpr(), F::D).toMst(evaluator), - evaluator, - ) -} - -/** - * Wraps this [MST] into [SymjaExpression] in the context of [algebra]. - */ -public fun > MST.toSymjaExpression(algebra: A): SymjaExpression = - SymjaExpression(algebra, this) diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt deleted file mode 100644 index 92f2474b8..000000000 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.symja - -import org.matheclipse.core.eval.ExprEvaluator -import org.matheclipse.core.expression.ComplexNum -import org.matheclipse.core.expression.F -import org.matheclipse.core.interfaces.IExpr -import org.matheclipse.core.interfaces.ISymbol -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.MstExtendedField -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.* - -internal val DEFAULT_EVALUATOR = ExprEvaluator(false, 100) - -/** - * Matches the given [IExpr] instance to appropriate [MST] node or evaluates it with [evaluator]. - */ -public fun IExpr.toMst(evaluator: ExprEvaluator = DEFAULT_EVALUATOR): MST = MstExtendedField { - when { - isPlus -> first().toMst(evaluator) + second().toMst(evaluator) - isSin -> sin(first().toMst(evaluator)) - isSinh -> sinh(first().toMst(evaluator)) - isCos -> cos(first().toMst(evaluator)) - isCosh -> cosh(first().toMst(evaluator)) - isTan -> tan(first().toMst(evaluator)) - isTanh -> tanh(first().toMst(evaluator)) - isArcSin -> asin(first().toMst(evaluator)) - isArcCos -> acos(first().toMst(evaluator)) - isArcTan -> atan(first().toMst(evaluator)) - isArcTanh -> atanh(first().toMst(evaluator)) - isE -> bindSymbol("e") - isPi -> bindSymbol("pi") - isTimes -> first().toMst(evaluator) * second().toMst(evaluator) - isOne -> one - isZero -> zero - isImaginaryUnit -> bindSymbol("i") - isMinusOne -> -one - this@toMst is ISymbol -> bindSymbol(symbolName) - isPower -> power(first().toMst(evaluator), evaluator.evalf(second())) - isExp -> exp(first().toMst(evaluator)) - isNumber -> number(evaluator.evalf(this@toMst)) - this@toMst === F.NIL -> error("NIL cannot be converted to MST") - else -> evaluator.eval(this@toMst.toString()).toMst(evaluator) - } -} - -/** - * Matches the given [MST] instance to appropriate [IExpr] node, only standard operations and symbols (which are - * present in, say, [MstExtendedField]) are supported. - */ -public fun MST.toIExpr(): IExpr = when (this) { - is MST.Numeric -> F.symjify(value) - - is Symbol -> when (identity) { - "e" -> F.E - "pi" -> F.Pi - "i" -> ComplexNum.I - else -> F.Dummy(identity) - } - - is MST.Unary -> when (operation) { - GroupOps.PLUS_OPERATION -> value.toIExpr() - GroupOps.MINUS_OPERATION -> F.Negate(value.toIExpr()) - TrigonometricOperations.SIN_OPERATION -> F.Sin(value.toIExpr()) - TrigonometricOperations.COS_OPERATION -> F.Cos(value.toIExpr()) - TrigonometricOperations.TAN_OPERATION -> F.Tan(value.toIExpr()) - TrigonometricOperations.ASIN_OPERATION -> F.ArcSin(value.toIExpr()) - TrigonometricOperations.ACOS_OPERATION -> F.ArcCos(value.toIExpr()) - TrigonometricOperations.ATAN_OPERATION -> F.ArcTan(value.toIExpr()) - ExponentialOperations.SINH_OPERATION -> F.Sinh(value.toIExpr()) - ExponentialOperations.COSH_OPERATION -> F.Cosh(value.toIExpr()) - ExponentialOperations.TANH_OPERATION -> F.Tanh(value.toIExpr()) - ExponentialOperations.ASINH_OPERATION -> F.ArcSinh(value.toIExpr()) - ExponentialOperations.ACOSH_OPERATION -> F.ArcCosh(value.toIExpr()) - ExponentialOperations.ATANH_OPERATION -> F.ArcTanh(value.toIExpr()) - PowerOperations.SQRT_OPERATION -> F.Sqrt(value.toIExpr()) - ExponentialOperations.EXP_OPERATION -> F.Exp(value.toIExpr()) - ExponentialOperations.LN_OPERATION -> F.Log(value.toIExpr()) - else -> error("Unary operation $operation not defined in $this") - } - - is MST.Binary -> when (operation) { - GroupOps.PLUS_OPERATION -> left.toIExpr() + right.toIExpr() - GroupOps.MINUS_OPERATION -> left.toIExpr() - right.toIExpr() - RingOps.TIMES_OPERATION -> left.toIExpr() * right.toIExpr() - FieldOps.DIV_OPERATION -> F.Divide(left.toIExpr(), right.toIExpr()) - PowerOperations.POW_OPERATION -> F.Power(left.toIExpr(), F.symjify((right as MST.Numeric).value)) - else -> error("Binary operation $operation not defined in $this") - } -} diff --git a/kmath-tensorflow/README.md b/kmath-tensorflow/README.md deleted file mode 100644 index a5b48de4d..000000000 --- a/kmath-tensorflow/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-tensorflow - -Google tensorflow connector - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-tensorflow:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-tensorflow:0.4.0-dev-1") -} -``` diff --git a/kmath-tensorflow/build.gradle.kts b/kmath-tensorflow/build.gradle.kts deleted file mode 100644 index 1e4ba12da..000000000 --- a/kmath-tensorflow/build.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -plugins { - id("space.kscience.gradle.jvm") -} - -description = "Google tensorflow connector" - -dependencies { - api(project(":kmath-tensors")) - api("org.tensorflow:tensorflow-core-api:0.4.0") - testImplementation("org.tensorflow:tensorflow-core-platform:0.4.0") -} - -readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE -} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt deleted file mode 100644 index 41c7c0b68..000000000 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensorflow - -import org.tensorflow.Graph -import org.tensorflow.Output -import org.tensorflow.ndarray.NdArray -import org.tensorflow.op.core.Constant -import org.tensorflow.types.TFloat64 -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.nd.ColumnStrides -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.PowerOperations - -public class DoubleTensorFlowOutput( - graph: Graph, - output: Output, -) : TensorFlowOutput(graph, output) { - - override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TFloat64 - -} - -internal fun ShapeND.toLongArray(): LongArray = LongArray(size) { get(it).toLong() } - -public class DoubleTensorFlowAlgebra internal constructor( - graph: Graph, -) : TensorFlowAlgebra(graph), PowerOperations> { - - override val elementAlgebra: DoubleField get() = DoubleField - - override fun structureND( - shape: ShapeND, - initializer: DoubleField.(IntArray) -> Double, - ): StructureND { - val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> - ColumnStrides(shape).forEach { index -> - array.setDouble(elementAlgebra.initializer(index), *index.toLongArray()) - } - } - return DoubleTensorFlowOutput(graph, ops.constant(res).asOutput()) - } - - override fun StructureND.asTensorFlow(): TensorFlowOutput = - if (this is TensorFlowOutput && output.type() == TFloat64::class.java) { - @Suppress("UNCHECKED_CAST") - this as TensorFlowOutput - } else { - val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> - @OptIn(PerformancePitfall::class) - elements().forEach { (index, value) -> - array.setDouble(value, *index.toLongArray()) - } - } - DoubleTensorFlowOutput(graph, ops.constant(res).asOutput()) - } - - override fun Output.wrap(): TensorFlowOutput = DoubleTensorFlowOutput(graph, this) - - override fun const(value: Double): Constant = ops.constant(value) - - override fun divide( - left: StructureND, - right: StructureND, - ): TensorFlowOutput = left.operate(right) { l, r -> - ops.math.div(l, r) - } - - override fun power(arg: StructureND, pow: Number): TensorFlowOutput = - arg.operate { ops.math.pow(it, const(pow.toDouble())) } -} - -/** - * Compute a tensor with TensorFlow in a single run. - * - * The resulting tensor is available outside of scope - */ -@UnstableKMathAPI -public fun DoubleField.produceWithTF( - block: DoubleTensorFlowAlgebra.() -> StructureND, -): StructureND = Graph().use { graph -> - val scope = DoubleTensorFlowAlgebra(graph) - scope.export(scope.block()) -} - -/** - * Compute several outputs with TensorFlow in a single run. - * - * The resulting tensors are available outside of scope - */ -@OptIn(UnstableKMathAPI::class) -public fun DoubleField.produceMapWithTF( - block: DoubleTensorFlowAlgebra.() -> Map>, -): Map> = Graph().use { graph -> - val scope = DoubleTensorFlowAlgebra(graph) - scope.block().mapValues { scope.export(it.value) } -} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt deleted file mode 100644 index 01c8054b3..000000000 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensorflow - -import org.tensorflow.Graph -import org.tensorflow.Output -import org.tensorflow.ndarray.NdArray -import org.tensorflow.types.TInt32 -import org.tensorflow.types.TInt64 - -public class IntTensorFlowOutput( - graph: Graph, - output: Output, -) : TensorFlowOutput(graph, output) { - override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TInt32 -} - -public class LongTensorFlowOutput( - graph: Graph, - output: Output, -) : TensorFlowOutput(graph, output) { - override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TInt64 -} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt deleted file mode 100644 index 73b36cd67..000000000 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensorflow - - -import org.tensorflow.Graph -import org.tensorflow.Operand -import org.tensorflow.Output -import org.tensorflow.Session -import org.tensorflow.ndarray.NdArray -import org.tensorflow.ndarray.index.Indices -import org.tensorflow.op.Ops -import org.tensorflow.op.core.* -import org.tensorflow.types.TInt32 -import org.tensorflow.types.family.TNumber -import org.tensorflow.types.family.TType -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnsafeKMathAPI -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.asArray -import space.kscience.kmath.nd.contentEquals -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.api.TensorAlgebra - -internal fun IntArray.toLongArray() = LongArray(size) { get(it).toLong() } -internal fun LongArray.toIntArray() = IntArray(size) { get(it).toInt() } - -internal val NdArray.scalar: T get() = getObject() - - -public sealed interface TensorFlowTensor : Tensor - -/** - * Static (eager) in-memory TensorFlow tensor - */ -@JvmInline -public value class TensorFlowArray(public val tensor: NdArray) : Tensor { - override val shape: ShapeND get() = ShapeND(tensor.shape().asArray().toIntArray()) - - @PerformancePitfall - override fun get(index: IntArray): T = tensor.getObject(*index.toLongArray()) - - //TODO implement native element sequence - - @PerformancePitfall - override fun set(index: IntArray, value: T) { - tensor.setObject(value, *index.toLongArray()) - } -} - -/** - * Lazy graph-based TensorFlow tensor. The tensor is actualized on call. - * - * If the tensor is used for intermediate operations, actualizing it could impact performance. - */ -public abstract class TensorFlowOutput( - protected val graph: Graph, - output: Output, -) : TensorFlowTensor { - - public var output: Output = output - internal set - - override val shape: ShapeND get() = ShapeND(output.shape().asArray().toIntArray()) - - protected abstract fun org.tensorflow.Tensor.actualizeTensor(): NdArray - - internal val actualTensor by lazy { - Session(graph).use { session -> - TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor()) - } - } - - @PerformancePitfall - override fun get(index: IntArray): T = actualTensor[index] - - @PerformancePitfall - override fun elements(): Sequence> = actualTensor.elements() - - @PerformancePitfall - override fun set(index: IntArray, value: T) { - actualTensor[index] = value - } - -} - - -public abstract class TensorFlowAlgebra> internal constructor( - protected val graph: Graph, -) : TensorAlgebra { - - public val ops: Ops by lazy { Ops.create(graph) } - - protected abstract fun StructureND.asTensorFlow(): TensorFlowOutput - - protected abstract fun Output.wrap(): TensorFlowOutput - - protected abstract fun const(value: T): Constant - - @OptIn(PerformancePitfall::class) - override fun StructureND.valueOrNull(): T? = if (shape contentEquals ShapeND(1)) - get(intArrayOf(0)) else null - - /** - * Perform binary lazy operation on tensor. Both arguments are implicitly converted - */ - public fun StructureND.operate( - other: StructureND, - operation: (left: Operand, right: Operand) -> Operand, - ): TensorFlowOutput { - val left = asTensorFlow().output - val right = other.asTensorFlow().output - return operation(left, right).asOutput().wrap() - } - - public fun T.operate( - other: StructureND, - operation: (left: Operand, right: Operand) -> Operand, - ): TensorFlowOutput { - val left = const(this) - val right = other.asTensorFlow().output - return operation(left, right).asOutput().wrap() - } - - public fun StructureND.operate( - value: T, - operation: (left: Operand, right: Operand) -> Operand, - ): TensorFlowOutput { - val left = asTensorFlow().output - val right = const(value) - return operation(left, right).asOutput().wrap() - } - - public fun Tensor.operateInPlace( - other: StructureND, - operation: (left: Operand, right: Operand) -> Operand, - ): Unit { - val origin = asTensorFlow() - val left = origin.output - val right = other.asTensorFlow().output - origin.output = operation(left, right).asOutput() - } - - public fun Tensor.operateInPlace( - value: T, - operation: (left: Operand, right: Operand) -> Operand, - ): Unit { - val origin = asTensorFlow() - val left = origin.output - val right = const(value) - origin.output = operation(left, right).asOutput() - } - - public fun StructureND.operate(operation: (Operand) -> Operand): TensorFlowOutput = - operation(asTensorFlow().output).asOutput().wrap() - - override fun T.plus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::add) - - override fun StructureND.plus(arg: T): TensorFlowOutput = operate(arg, ops.math::add) - - override fun StructureND.plus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::add) - - override fun Tensor.plusAssign(value: T): Unit = operateInPlace(value, ops.math::add) - - override fun Tensor.plusAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::add) - - override fun StructureND.minus(arg: T): TensorFlowOutput = operate(arg, ops.math::sub) - - override fun StructureND.minus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::sub) - - override fun T.minus(arg: StructureND): Tensor = operate(arg, ops.math::sub) - - override fun Tensor.minusAssign(value: T): Unit = operateInPlace(value, ops.math::sub) - - override fun Tensor.minusAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::sub) - - override fun T.times(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::mul) - - override fun StructureND.times(arg: T): TensorFlowOutput = operate(arg, ops.math::mul) - - override fun StructureND.times(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::mul) - - override fun Tensor.timesAssign(value: T): Unit = operateInPlace(value, ops.math::mul) - - override fun Tensor.timesAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::mul) - - override fun StructureND.unaryMinus(): TensorFlowOutput = operate(ops.math::neg) - - override fun Tensor.getTensor(i: Int): Tensor = operate { - StridedSliceHelper.stridedSlice(ops.scope(), it, Indices.at(i.toLong())) - } - - override fun StructureND.transposed(i: Int, j: Int): Tensor = operate { - ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) - } - - override fun Tensor.view(shape: ShapeND): Tensor = operate { - @OptIn(UnsafeKMathAPI::class) - ops.reshape(it, ops.constant(shape.asArray())) - } - - override fun Tensor.viewAs(other: StructureND): Tensor = operate(other) { l, r -> - ops.reshape(l, ops.shape(r)) - } - - override fun StructureND.dot(other: StructureND): TensorFlowOutput = operate(other) { l, r -> - ops.linalg.matMul( - if (l.shape().numDimensions() == 1) ops.expandDims(l, ops.constant(0)) else l, - if (r.shape().numDimensions() == 1) ops.expandDims(r, ops.constant(-1)) else r - ) - } - - override fun diagonalEmbedding( - diagonalEntries: StructureND, - offset: Int, - dim1: Int, - dim2: Int, - ): TensorFlowOutput = diagonalEntries.operate { - ops.linalg.matrixDiagV3( - /* diagonal = */ it, - /* k = */ ops.constant(offset), - /* numRows = */ ops.constant(dim1), - /* numCols = */ ops.constant(dim2), - /* paddingValue = */ const(elementAlgebra.zero) - ) - } - - override fun StructureND.sum(): T = operate { - ops.sum(it, ops.constant(intArrayOf())) - }.value() - - override fun StructureND.sum(dim: Int, keepDim: Boolean): TensorFlowOutput = operate { - ops.sum(it, ops.constant(dim), Sum.keepDims(keepDim)) - } - - override fun StructureND.min(): T = operate { - ops.min(it, ops.constant(intArrayOf())) - }.value() - - override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor = operate { - ops.min(it, ops.constant(dim), Min.keepDims(keepDim)) - } - - override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = IntTensorFlowOutput( - graph, - ops.math.argMin(asTensorFlow().output, ops.constant(dim), TInt32::class.java).output() - ).actualTensor - - override fun StructureND.max(): T = operate { - ops.max(it, ops.constant(intArrayOf())) - }.value() - - override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor = operate { - ops.max(it, ops.constant(dim), Max.keepDims(keepDim)) - } - - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor = IntTensorFlowOutput( - graph, - ops.math.argMax(asTensorFlow().output, ops.constant(dim), TInt32::class.java).output() - ).actualTensor - -// private val symbolCache = HashMap>() -// -// override fun bindSymbolOrNull(value: String): TensorFlowOutput? { -// return symbolCache.getOrPut(value){ops.var} -// } -// -// public fun StructureND.grad( -// -// )= operate { ops.gradients() } - - @OptIn(UnstableKMathAPI::class) - override fun export(arg: StructureND): StructureND = - if (arg is TensorFlowOutput) arg.actualTensor else arg -} - -//TODO add TensorFlow expressions \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt deleted file mode 100644 index a0a2ddc80..000000000 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensorflow - -import org.tensorflow.types.family.TNumber -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.TrigonometricOperations - -// - -// TODO add other operations - -public fun TensorFlowAlgebra.sin( - arg: StructureND, -): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.sin(it) } - -public fun TensorFlowAlgebra.cos( - arg: StructureND, -): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.cos(it) } \ No newline at end of file diff --git a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt deleted file mode 100644 index 730feede6..000000000 --- a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensorflow - -import org.junit.jupiter.api.Test -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.sum -import space.kscience.kmath.tensors.core.randomNormal -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class DoubleTensorFlowOps { - @Test - fun basicOps() { - val res = DoubleField.produceWithTF { - val initial = structureND(2, 2) { 1.0 } - - initial + (initial * 2.0) - } - //println(StructureND.toString(res)) - assertEquals(3.0, res[0, 0]) - } - - @Test - fun dot(){ - val dim = 1000 - - val tensor1 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12224) - val tensor2 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12225) - - DoubleField.produceWithTF { - tensor1 dot tensor2 - }.sum() - } - - @Test - fun extensionOps(){ - val res = DoubleField.produceWithTF { - val i = structureND(2, 2) { 0.5 } - - sin(i).pow(2) + cos(i).pow(2) - } - - assertEquals(1.0, res[0,0],0.01) - } - - -} \ No newline at end of file diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md deleted file mode 100644 index 80f751ffe..000000000 --- a/kmath-tensors/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Module kmath-tensors - -Common linear algebra operations on tensors. - - - [tensor algebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) - - [tensor algebra with broadcasting](src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. - - [linear algebra operations](src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-tensors:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-tensors:0.4.0-dev-1") -} -``` diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts deleted file mode 100644 index 79c39bae7..000000000 --- a/kmath-tensors/build.gradle.kts +++ /dev/null @@ -1,50 +0,0 @@ -plugins { - id("space.kscience.gradle.mpp") -} - -kscience{ - jvm() - js() - native() - - dependencies { - api(projects.kmathCore) - api(projects.kmathStat) - } -} - -kotlin.sourceSets { - - commonMain { - dependencies { - api(project(":kmath-core")) - api(project(":kmath-stat")) - } - } - - commonTest{ - dependencies{ - implementation(projects.testUtils) - } - } -} - -readme { - maturity = space.kscience.gradle.Maturity.PROTOTYPE - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature( - id = "tensor algebra", - ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt" - ) { "Basic linear algebra operations on tensors (plus, dot, etc.)" } - - feature( - id = "tensor algebra with broadcasting", - ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt" - ) { "Basic linear algebra operations implemented with broadcasting." } - - feature( - id = "linear algebra operations", - ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt" - ) { "Advanced linear algebra operations like LU decomposition, SVD, etc." } -} diff --git a/kmath-tensors/docs/README-TEMPLATE.md b/kmath-tensors/docs/README-TEMPLATE.md deleted file mode 100644 index 5fd968afd..000000000 --- a/kmath-tensors/docs/README-TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -# Module kmath-tensors - -Common linear algebra operations on tensors. - -${features} - -${artifact} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt deleted file mode 100644 index 1a324b200..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.api - -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.ExtendedFieldOps -import space.kscience.kmath.operations.Field - - -/** - * Analytic operations on [Tensor]. - * - * @param T the type of items closed under analytic functions in the tensors. - */ -public interface AnalyticTensorAlgebra> : - TensorPartialDivisionAlgebra, ExtendedFieldOps> { - - /** - * @return the mean of all elements in the input tensor. - */ - public fun mean(structureND: StructureND): T - - /** - * Returns the mean of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the mean of each row of the input tensor in the given dimension [dim]. - */ - public fun mean(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor - - /** - * @return the standard deviation of all elements in the input tensor. - */ - public fun std(structureND: StructureND): T - - /** - * Returns the standard deviation of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the standard deviation of each row of the input tensor in the given dimension [dim]. - */ - public fun std(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor - - /** - * @return the variance of all elements in the input tensor. - */ - public fun variance(structureND: StructureND): T - - /** - * Returns the variance of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the variance of each row of the input tensor in the given dimension [dim]. - */ - public fun variance(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.sqrt.html - override fun sqrt(arg: StructureND): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.atan.html#torch.tan - override fun tan(arg: StructureND): Tensor - - //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.atan - override fun atan(arg: StructureND): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.tanh - override fun tanh(arg: StructureND): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.ceil.html#torch.ceil - public fun ceil(arg: StructureND): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor - public fun floor(structureND: StructureND): Tensor - - override fun sin(arg: StructureND): StructureND - - override fun cos(arg: StructureND): StructureND - - override fun asin(arg: StructureND): StructureND - - override fun acos(arg: StructureND): StructureND - - override fun exp(arg: StructureND): StructureND - - override fun ln(arg: StructureND): StructureND - - override fun sinh(arg: StructureND): StructureND - - override fun cosh(arg: StructureND): StructureND - - override fun asinh(arg: StructureND): StructureND - - override fun acosh(arg: StructureND): StructureND - - override fun atanh(arg: StructureND): StructureND -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt deleted file mode 100644 index faff2eb80..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.api - -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Field - -/** - * Common linear algebra operations. Operates on [Tensor]. - * - * @param T the type of items closed under division in the tensors. - */ -public interface LinearOpsTensorAlgebra> : TensorPartialDivisionAlgebra { - - /** - * Computes the determinant of a square matrix input, or of each square matrix in a batched input. - * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.det - * - * @return the determinant. - */ - public fun StructureND.det(): StructureND - - /** - * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. - * Given a square matrix `A`, return the matrix `AInv` satisfying - * `A dot AInv == AInv dot A == eye(a.shape[0])`. - * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv - * - * @return the multiplicative inverse of a matrix. - */ - public fun StructureND.inv(): StructureND - - /** - * Cholesky decomposition. - * - * Computes the Cholesky decomposition of a Hermitian (or symmetric for real-valued matrices) - * positive-definite matrix or the Cholesky decompositions for a batch of such matrices. - * Each decomposition has the form: - * Given a tensor `input`, return the tensor `L` satisfying `input = L dot LH`, - * where `L` is a lower-triangular matrix and `LH` is the conjugate transpose of `L`, - * which is just a transpose for the case of real-valued input matrices. - * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky - * - * @receiver the `input`. - * @return the batch of `L` matrices. - */ - public fun cholesky(structureND: StructureND): StructureND - - /** - * QR decomposition. - * - * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `Q to R` of tensors. - * Given a tensor `input`, return tensors `Q to R` satisfying `input == Q dot R`, - * with `Q` being an orthogonal matrix or batch of orthogonal matrices - * and `R` being an upper triangular matrix or batch of upper triangular matrices. - * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr - * - * @receiver the `input`. - * @return pair of `Q` and `R` tensors. - */ - public fun qr(structureND: StructureND): Pair, StructureND> - - /** - * LUP decomposition - * - * Computes the LUP decomposition of a matrix or a batch of matrices. - * Given a tensor `input`, return tensors (P, L, U) satisfying `P dot input = L dot U`, - * with `P` being a permutation matrix or batch of matrices, - * `L` being a lower triangular matrix or batch of matrices, - * `U` being an upper triangular matrix or batch of matrices. - * - * @receiver the `input`. - * @return triple of P, L and U tensors - */ - public fun lu(structureND: StructureND): Triple, StructureND, StructureND> - - /** - * Singular Value Decomposition. - * - * Computes the singular value decomposition of either a matrix or batch of matrices `input`. - * The singular value decomposition is represented as a triple `Triple(U, S, V)`, - * such that `input = U dot diagonalEmbedding(S) dot VH`, - * where `VH` is the conjugate transpose of V. - * If `input` is a batch of tensors, then `U`, `S`, and `VH` are also batched with the same batch dimensions as - * `input`. - * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd - * - * @receiver the `input`. - * @return triple `Triple(U, S, V)`. - */ - public fun svd(structureND: StructureND): Triple, StructureND, StructureND> - - /** - * Returns eigenvalues and eigenvectors of a real symmetric matrix `input` or a batch of real symmetric matrices, - * represented by a pair `eigenvalues to eigenvectors`. - * For more information: https://pytorch.org/docs/stable/generated/torch.symeig.html - * - * @receiver the `input`. - * @return a pair `eigenvalues to eigenvectors` - */ - public fun symEig(structureND: StructureND): Pair, StructureND> - -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt deleted file mode 100644 index b328fbeec..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.api - -import space.kscience.kmath.nd.MutableStructureND - -public typealias Tensor = MutableStructureND diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt deleted file mode 100644 index f923400c5..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.api - -import space.kscience.kmath.nd.RingOpsND -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Ring - -/** - * Algebra over a ring on [Tensor]. - * For more information: https://proofwiki.org/wiki/Definition:Algebra_over_Ring - * - * @param T the type of items in the tensors. - */ -public interface TensorAlgebra> : RingOpsND { - /** - * Returns a single tensor value of unit dimension if tensor shape equals to [1]. - * - * @return a nullable value of a potentially scalar tensor. - */ - public fun StructureND.valueOrNull(): T? - - /** - * Returns a single tensor value of unit dimension. The tensor shape must be equal to [1]. - * - * @return the value of a scalar tensor. - */ - public fun StructureND.value(): T = - valueOrNull() ?: throw IllegalArgumentException("Inconsistent value for tensor of with $shape shape") - - /** - * Each element of the tensor [arg] is added to this value. - * The resulting tensor is returned. - * - * @param arg tensor to be added. - * @return the sum of this value and tensor [arg]. - */ - override operator fun T.plus(arg: StructureND): Tensor - - /** - * Adds the scalar [arg] to each element of this tensor and returns a new resulting tensor. - * - * @param arg the number to be added to each element of this tensor. - * @return the sum of this tensor and [arg]. - */ - override operator fun StructureND.plus(arg: T): Tensor - - /** - * Each element of the tensor [arg] is added to each element of this tensor. - * The resulting tensor is returned. - * - * @param arg tensor to be added. - * @return the sum of this tensor and [arg]. - */ - override operator fun StructureND.plus(arg: StructureND): Tensor - - /** - * Adds the scalar [value] to each element of this tensor. - * - * @param value the number to be added to each element of this tensor. - */ - public operator fun Tensor.plusAssign(value: T) - - /** - * Each element of the tensor [arg] is added to each element of this tensor. - * - * @param arg tensor to be added. - */ - public operator fun Tensor.plusAssign(arg: StructureND) - - /** - * Each element of the tensor [arg] is subtracted from this value. - * The resulting tensor is returned. - * - * @param arg tensor to be subtracted. - * @return the difference between this value and tensor [arg]. - */ - override operator fun T.minus(arg: StructureND): Tensor - - /** - * Subtracts the scalar [arg] from each element of this tensor and returns a new resulting tensor. - * - * @param arg the number to be subtracted from each element of this tensor. - * @return the difference between this tensor and [arg]. - */ - override operator fun StructureND.minus(arg: T): Tensor - - /** - * Each element of the tensor [arg] is subtracted from each element of this tensor. - * The resulting tensor is returned. - * - * @param arg tensor to be subtracted. - * @return the difference between this tensor and [arg]. - */ - override operator fun StructureND.minus(arg: StructureND): Tensor - - /** - * Subtracts the scalar [value] from each element of this tensor. - * - * @param value the number to be subtracted from each element of this tensor. - */ - public operator fun Tensor.minusAssign(value: T) - - /** - * Each element of the tensor [arg] is subtracted from each element of this tensor. - * - * @param arg tensor to be subtracted. - */ - public operator fun Tensor.minusAssign(arg: StructureND) - - - /** - * Each element of the tensor [arg] is multiplied by this value. - * The resulting tensor is returned. - * - * @param arg tensor to be multiplied. - * @return the product of this value and tensor [arg]. - */ - override operator fun T.times(arg: StructureND): Tensor - - /** - * Multiplies the scalar [arg] by each element of this tensor and returns a new resulting tensor. - * - * @param arg the number to be multiplied by each element of this tensor. - * @return the product of this tensor and [arg]. - */ - override operator fun StructureND.times(arg: T): Tensor - - /** - * Each element of the tensor [arg] is multiplied by each element of this tensor. - * The resulting tensor is returned. - * - * @param arg tensor to be multiplied. - * @return the product of this tensor and [arg]. - */ - override operator fun StructureND.times(arg: StructureND): Tensor - - /** - * Multiplies the scalar [value] by each element of this tensor. - * - * @param value the number to be multiplied by each element of this tensor. - */ - public operator fun Tensor.timesAssign(value: T) - - /** - * Each element of the tensor [arg] is multiplied by each element of this tensor. - * - * @param arg tensor to be multiplied. - */ - public operator fun Tensor.timesAssign(arg: StructureND) - - /** - * Numerical negative, element-wise. - * - * @return tensor negation of the original tensor. - */ - override operator fun StructureND.unaryMinus(): Tensor - - /** - * Returns the tensor at index i - * For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html - * - * @param i index of the extractable tensor - * @return subtensor of the original tensor with index [i] - */ - public fun Tensor.getTensor(i: Int): Tensor - - public fun Tensor.getTensor(first: Int, second: Int): Tensor { - return getTensor(first).getTensor(second) - } - - /** - * Returns a tensor that is a transposed version of this tensor. The given dimensions [i] and [j] are swapped. - * For more information: https://pytorch.org/docs/stable/generated/torch.transpose.html - * - * If axis indices are negative, they are counted from shape end. - * - * @param i the first dimension to be transposed - * @param j the second dimension to be transposed - * @return transposed tensor - */ - public fun StructureND.transposed(i: Int = shape.size - 2, j: Int = shape.size - 1): Tensor - - /** - * Returns a new tensor with the same data as the self tensor but of a different shape. - * The returned tensor shares the same data and must have the same number of elements, but may have a different size - * For more information: https://pytorch.org/docs/stable/tensor_view.html - * - * @param shape the desired size - * @return tensor with new shape - */ - public fun Tensor.view(shape: ShapeND): Tensor - - /** - * View this tensor as the same size as [other]. - * `this.viewAs(other)` is equivalent to `this.view(other.shape)`. - * For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html - * - * @param other the result tensor has the same size as other. - * @return the result tensor with the same size as other. - */ - public fun Tensor.viewAs(other: StructureND): Tensor - - /** - * Matrix product of two tensors. - * - * The behavior depends on the dimensionality of the tensors as follows: - * 1. If both tensors are 1-dimensional, the dot product (scalar) is returned. - * - * 2. If both arguments are 2-dimensional, the matrix-matrix product is returned. - * - * 3. If the first argument is 1-dimensional and the second argument is 2-dimensional, - * a 1 is prepended to its dimension for the purpose of the matrix multiply. - * After the matrix multiply, depending on the implementation the prepended dimension might be removed. - * - * 4. If the first argument is 2-dimensional and the second argument is 1-dimensional, - * the matrix-vector product is returned. - * - * Otherwise, throw an exception. - * - * @param other tensor to be multiplied. - * @return a mathematical product of two tensors. - */ - public infix fun StructureND.dot(other: StructureND): Tensor - - /** - * Creates a tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) - * are filled by [diagonalEntries]. - * To facilitate creating batched diagonal matrices, - * the 2D planes formed by the last two dimensions of the returned tensor are chosen by default. - * - * The argument [offset] controls, which diagonal to consider: - * 1. If [offset] = 0, it is the main diagonal. - * 1. If [offset] > 0, it is above the main diagonal. - * 1. If [offset] < 0, it is below the main diagonal. - * - * The size of the new matrix will be calculated - * to make the specified diagonal of the size of the last input dimension. - * For more information: https://pytorch.org/docs/stable/generated/torch.diag_embed.html - * - * @param diagonalEntries the input tensor. Must be at least 1-dimensional. - * @param offset which diagonal to consider. Default: 0 (main diagonal). - * @param dim1 first dimension with respect to which to take diagonal. Default: -2. - * @param dim2 second dimension with respect to which to take diagonal. Default: -1. - * - * @return tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) - * are filled by [diagonalEntries] - */ - public fun diagonalEmbedding( - diagonalEntries: StructureND, - offset: Int = 0, - dim1: Int = -2, - dim2: Int = -1, - ): Tensor - - /** - * @return the sum of all elements in the input tensor. - */ - public fun StructureND.sum(): T - - /** - * Returns the sum of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the sum of each row of the input tensor in the given dimension [dim]. - */ - public fun StructureND.sum(dim: Int, keepDim: Boolean): Tensor - - /** - * @return the minimum value of all elements in the input tensor or null if there are no values - */ - public fun StructureND.min(): T? - - /** - * Returns the minimum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the minimum value of each row of the input tensor in the given dimension [dim]. - */ - public fun StructureND.min(dim: Int, keepDim: Boolean): Tensor - - /** - * Returns the index of minimum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the index of maximum value of each row of the input tensor in the given dimension [dim]. - */ - public fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor - - /** - * Returns the maximum value of all elements in the input tensor or null if there are no values - */ - public fun StructureND.max(): T? - - /** - * Returns the maximum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the maximum value of each row of the input tensor in the given dimension [dim]. - */ - public fun StructureND.max(dim: Int, keepDim: Boolean): Tensor - - /** - * Returns the index of maximum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the index of maximum value of each row of the input tensor in the given dimension [dim]. - */ - public fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor - - override fun add(left: StructureND, right: StructureND): Tensor = left + right - - override fun multiply(left: StructureND, right: StructureND): Tensor = left * right -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt deleted file mode 100644 index 33effb2d2..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.api - -import space.kscience.kmath.nd.FieldOpsND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Field - -/** - * Algebra over a field with partial division on [Tensor]. - * For more information: https://proofwiki.org/wiki/Definition:Division_Algebra - * - * @param T the type of items closed under division in the tensors. - */ -public interface TensorPartialDivisionAlgebra> : TensorAlgebra, FieldOpsND { - - /** - * Each element of the tensor [arg] is divided by this value. - * The resulting tensor is returned. - * - * @param arg tensor to divide by. - * @return the division of this value by the tensor [arg]. - */ - override operator fun T.div(arg: StructureND): Tensor - - /** - * Divide by the scalar [arg] each element of this tensor returns a new resulting tensor. - * - * @param arg the number to divide by each element of this tensor. - * @return the division of this tensor by the [arg]. - */ - override operator fun StructureND.div(arg: T): Tensor - - /** - * Each element of the tensor [arg] is divided by each element of this tensor. - * The resulting tensor is returned. - * - * @param arg tensor to be divided by. - * @return the division of this tensor by [arg]. - */ - override operator fun StructureND.div(arg: StructureND): Tensor - - override fun divide(left: StructureND, right: StructureND): StructureND = left.div(right) - - /** - * Divides by the scalar [value] each element of this tensor. - * - * @param value the number to divide by each element of this tensor. - */ - public operator fun Tensor.divAssign(value: T) - - /** - * Each element of this tensor is divided by each element of the [arg] tensor. - * - * @param arg tensor to be divided by. - */ - public operator fun Tensor.divAssign(arg: StructureND) -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt deleted file mode 100644 index 7db91722f..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.broadcastTensors -import space.kscience.kmath.tensors.core.internal.broadcastTo - -/** - * Basic linear algebra operations implemented with broadcasting. - * For more information: https://pytorch.org/docs/stable/notes/broadcasting.html - */ -public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - - override fun StructureND.plus(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i -> - newThis.source[i] + newOther.source[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun Tensor.plusAssign(arg: StructureND) { - val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) - for (i in 0 until asDoubleTensor().indices.linearSize) { - asDoubleTensor().source[i] += newOther.source[i] - } - } - - override fun StructureND.minus(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i -> - newThis.source[i] - newOther.source[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun Tensor.minusAssign(arg: StructureND) { - val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) - for (i in 0 until indices.linearSize) { - asDoubleTensor().source[i] -= newOther.source[i] - } - } - - override fun StructureND.times(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i -> - newThis.source[i] * newOther.source[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun Tensor.timesAssign(arg: StructureND) { - val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) - for (i in 0 until indices.linearSize) { - asDoubleTensor().source[+i] *= newOther.source[i] - } - } - - override fun StructureND.div(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i -> - newThis.source[i] / newOther.source[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun Tensor.divAssign(arg: StructureND) { - val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) - for (i in 0 until indices.linearSize) { - asDoubleTensor().source[i] /= newOther.source[i] - } - } -} - - -/** - * Compute a value using broadcast double tensor algebra - */ -@UnstableKMathAPI -public fun DoubleTensorAlgebra.withBroadcast(block: BroadcastDoubleTensorAlgebra.() -> R): R = - BroadcastDoubleTensorAlgebra.block() \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt deleted file mode 100644 index eaec43e2c..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.RowStrides -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.Strides -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.tensors.api.Tensor - -/** - * Represents [Tensor] over a [MutableBuffer] intended to be used through [DoubleTensor] and [IntTensor] - */ -public abstract class BufferedTensor( - override val shape: ShapeND, -) : Tensor { - - public abstract val source: MutableBuffer - - /** - * Buffer strides based on [RowStrides] implementation - */ - override val indices: Strides get() = RowStrides(shape) - - /** - * Number of elements in tensor - */ - public val linearSize: Int get() = indices.linearSize - - - @PerformancePitfall - override fun elements(): Sequence> = indices.asSequence().map { - it to get(it) - } -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt deleted file mode 100644 index d2c2e9d5d..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.MutableStructureNDOfDouble -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.structures.* -import space.kscience.kmath.tensors.core.internal.toPrettyString - -public class OffsetDoubleBuffer( - override val origin: DoubleBuffer, - private val offset: Int, - override val size: Int, -) : MutableBuffer, BufferView { - - init { - require(offset >= 0) { "Offset must be non-negative" } - require(size >= 0) { "Size must be non-negative" } - require(offset + size <= origin.size) { "Maximum index must be inside source dimension" } - } - - override fun set(index: Int, value: Double) { - require(index in 0 until size) { "Index must be in [0, size)" } - origin[index + offset] = value - } - - override fun get(index: Int): Double = origin[index + offset] - - /** - * Copy only a part of buffer that belongs to this [OffsetDoubleBuffer] - */ - override fun copy(): DoubleBuffer = origin.array.copyOfRange(offset, offset + size).asBuffer() - - override fun iterator(): Iterator = iterator { - for (i in indices) { - yield(get(i)) - } - } - - override fun toString(): String = Buffer.toString(this) - - public fun view(addOffset: Int, newSize: Int = size - addOffset): OffsetDoubleBuffer = - OffsetDoubleBuffer(origin, offset + addOffset, newSize) - - @UnstableKMathAPI - override fun originIndex(index: Int): Int = if (index in 0 until size) { - index + offset - } else { - -1 - } -} - -public fun OffsetDoubleBuffer.slice(range: IntRange): OffsetDoubleBuffer = view(range.first, range.last - range.first) - -/** - * Map only operable content of the offset buffer - */ -public inline fun OffsetDoubleBuffer.map(operation: (Double) -> Double): DoubleBuffer = - DoubleBuffer(size) { operation(get(it)) } - -public inline fun OffsetDoubleBuffer.zip( - other: OffsetDoubleBuffer, - operation: (l: Double, r: Double) -> Double, -): DoubleBuffer { - require(size == other.size) { "The sizes of zipped buffers must be the same" } - return DoubleBuffer(size) { operation(get(it), other[it]) } -} - -/** - * map in place - */ -public inline fun OffsetDoubleBuffer.mapInPlace(operation: (Double) -> Double) { - indices.forEach { set(it, operation(get(it))) } -} - -/** - * Default [BufferedTensor] implementation for [Double] values. - * - * [DoubleTensor] always uses row-based strides - */ -public open class DoubleTensor( - shape: ShapeND, - final override val source: OffsetDoubleBuffer, -) : BufferedTensor(shape), MutableStructureNDOfDouble { - - init { - require(linearSize == source.size) { "Source buffer size must be equal tensor size" } - } - - public constructor(shape: ShapeND, buffer: DoubleBuffer) : this(shape, OffsetDoubleBuffer(buffer, 0, buffer.size)) - - - @OptIn(PerformancePitfall::class) - override fun get(index: IntArray): Double = source[indices.offset(index)] - - @OptIn(PerformancePitfall::class) - override fun set(index: IntArray, value: Double) { - source[indices.offset(index)] = value - } - - override fun getDouble(index: IntArray): Double = source[indices.offset(index)] - - override fun setDouble(index: IntArray, value: Double) { - set(index, value) - } - - override fun toString(): String = toPrettyString() -} - -public fun DoubleTensor.asDoubleBuffer(): OffsetDoubleBuffer = if (shape.size == 1) { - source -} else { - error("Only 1D tensors could be cast to 1D") -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt deleted file mode 100644 index d2066e404..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.MutableStructure1D -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.structures.MutableBuffer - -public class DoubleTensor1D( - source: OffsetDoubleBuffer, -) : DoubleTensor(ShapeND(source.size), source), MutableStructure1D { - - @PerformancePitfall - override fun get(index: IntArray): Double = super.get(index) - - @PerformancePitfall - override fun set(index: IntArray, value: Double) { - super.set(index, value) - } - - override val size: Int get() = source.size - - override fun get(index: Int): Double = source[index] - - override fun set(index: Int, value: Double) { - source[index] = value - } - - override fun copy(): MutableBuffer = source.copy() - - @PerformancePitfall - override fun elements(): Sequence> = super.elements() -} - -/** - * A zero-copy cast to 1D structure. Changes in resulting structure are reflected on original tensor. - */ -public fun DoubleTensor.asDoubleTensor1D(): DoubleTensor1D { - require(shape.size == 1) { "Only 1D tensors could be cast to 1D" } - return DoubleTensor1D(source) -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt deleted file mode 100644 index fa142afa0..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.MutableStructure2D -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.linearSize -import space.kscience.kmath.structures.PermutedMutableBuffer -import space.kscience.kmath.structures.permute - -public class DoubleTensor2D( - override val rowNum: Int, - override val colNum: Int, - source: OffsetDoubleBuffer, -) : DoubleTensor(ShapeND(rowNum, colNum), source), MutableStructure2D { - - override fun get(i: Int, j: Int): Double = source[i * colNum + j] - - @OptIn(PerformancePitfall::class) - override fun get(index: IntArray): Double = getDouble(index) - - override fun set(i: Int, j: Int, value: Double) { - source[i * colNum + j] = value - } - - @OptIn(PerformancePitfall::class) - override val rows: List - get() = List(rowNum) { i -> - source.view(i * colNum, colNum) - } - - - @OptIn(PerformancePitfall::class) - override val columns: List> - get() = List(colNum) { j -> - val indices = IntArray(rowNum) { i -> j + i * colNum } - source.permute(indices) - } - - override val shape: ShapeND get() = super.shape - - @PerformancePitfall - override fun elements(): Sequence> = super.elements() -} - -/** - * A zero-copy cast to 2D structure. Changes in resulting structure are reflected on original tensor. - */ -public fun DoubleTensor.asDoubleTensor2D(): DoubleTensor2D { - require(shape.size == 2) { "Only 2D tensors could be cast to 2D" } - return DoubleTensor2D(shape[0], shape[1], source) -} - - -public inline fun DoubleTensor.forEachMatrix(block: (index: IntArray, matrix: DoubleTensor2D) -> Unit) { - val n = shape.size - check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } - val matrixOffset = shape[n - 1] * shape[n - 2] - val matrixShape = ShapeND(shape[n - 2], shape[n - 1]) - - val size = matrixShape.linearSize - for (i in 0 until linearSize / matrixOffset) { - val offset = i * matrixOffset - val index = indices.index(offset).sliceArray(0 until (shape.size - 2)) - block(index, DoubleTensor(matrixShape, source.view(offset, size)).asDoubleTensor2D()) - } -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt deleted file mode 100644 index 70a3ef7e2..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ /dev/null @@ -1,719 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - - -@file:OptIn(PerformancePitfall::class) - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleBufferOps -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.* -import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra -import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.* -import kotlin.math.abs -import kotlin.math.ceil -import kotlin.math.floor -import kotlin.math.sqrt - -/** - * Implementation of basic operations over double tensors and basic algebra operations on them. - */ -@OptIn(PerformancePitfall::class) -public open class DoubleTensorAlgebra : - AnalyticTensorAlgebra, - LinearOpsTensorAlgebra { - - public companion object : DoubleTensorAlgebra() - - override val elementAlgebra: DoubleField get() = DoubleField - - public val bufferAlgebra: DoubleBufferOps get() = DoubleBufferOps - - - /** - * Applies the [transform] function to each element of the tensor and returns the resulting modified tensor. - * - * @param transform the function to be applied to each element of the tensor. - * @return the resulting tensor after applying the function. - */ - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun StructureND.map(transform: DoubleField.(Double) -> Double): DoubleTensor { - val tensor = asDoubleTensor() - //TODO remove additional copy - val array = DoubleBuffer(tensor.source.size) { DoubleField.transform(tensor.source[it]) } - return DoubleTensor( - tensor.shape, - array, - ) - } - - public inline fun Tensor.mapInPlace(operation: (Double) -> Double) { - if (this is DoubleTensor) { - source.mapInPlace(operation) - } else { - indices.forEach { set(it, operation(get(it))) } - } - } - - public inline fun Tensor.mapIndexedInPlace(operation: DoubleField.(IntArray, Double) -> Double) { - indices.forEach { set(it, DoubleField.operation(it, get(it))) } - } - - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun StructureND.mapIndexed(transform: DoubleField.(index: IntArray, Double) -> Double): DoubleTensor { - return copyToTensor().apply { mapIndexedInPlace(transform) } - } - - - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun zip( - left: StructureND, - right: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): DoubleTensor { - checkShapesCompatible(left, right) - - val leftTensor = left.asDoubleTensor() - val rightTensor = right.asDoubleTensor() - val buffer = DoubleBuffer(leftTensor.source.size) { - DoubleField.transform(leftTensor.source[it], rightTensor.source[it]) - } - return DoubleTensor(leftTensor.shape, buffer) - } - - - public inline fun StructureND.reduceElements(transform: (DoubleBuffer) -> Double): Double = - transform(asDoubleTensor().source.copy()) - //TODO Add read-only DoubleBuffer wrapper. To avoid protective copy - - override fun StructureND.valueOrNull(): Double? { - val dt = asDoubleTensor() - return if (dt.shape contentEquals ShapeND(1)) dt.source[0] else null - } - - override fun StructureND.value(): Double = valueOrNull() - ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") - - public fun fromBuffer(shape: ShapeND, buffer: Buffer): DoubleTensor { - checkNotEmptyShape(shape) - check(buffer.size > 0) { "Illegal empty buffer provided" } - check(buffer.size == shape.linearSize) { - "Inconsistent shape $shape for buffer of size ${buffer.size} provided" - } - return DoubleTensor(shape, buffer.toDoubleBuffer()) - } - - - /** - * Constructs a tensor with the specified shape and data. - * - * @param shape the desired shape for the tensor. - * @param array one-dimensional data array. - * @return tensor with the [shape] shape and [array] data. - */ - public fun fromArray(shape: ShapeND, array: DoubleArray): DoubleTensor = fromBuffer(shape, array.asBuffer()) - - /** - * Constructs a tensor with the specified shape and initializer. - * - * @param shape the desired shape for the tensor. - * @param initializer mapping tensor indices to values. - * @return tensor with the [shape] shape and data generated by the [initializer]. - */ - override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleTensor = fromArray( - shape, - RowStrides(shape).asSequence().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray() - ) - - override fun Tensor.getTensor(i: Int): DoubleTensor { - val dt = asDoubleTensor() - val lastShape = shape.last(shape.size - 1) - val newShape: ShapeND = if (lastShape.isNotEmpty()) lastShape else ShapeND(1) - return DoubleTensor( - newShape, - dt.source.view(newShape.linearSize * i, newShape.linearSize) - ) - } - - /** - * Creates a tensor of a given shape and fills all elements with a given value. - * - * @param value the value to fill the output tensor with. - * @param shape array of integers defining the shape of the output tensor. - * @return tensor with the [shape] shape and filled with [value]. - */ - public fun full(value: Double, shape: ShapeND): DoubleTensor { - checkNotEmptyShape(shape) - val buffer = DoubleBuffer(shape.linearSize) { value } - return DoubleTensor(shape, buffer) - } - - /** - * Returns a tensor with the same shape as `input` filled with [value]. - * - * @param value the value to fill the output tensor with. - * @return tensor with the `input` tensor shape and filled with [value]. - */ - public fun fullLike(structureND: StructureND<*>, value: Double): DoubleTensor { - val shape = structureND.shape - val buffer = DoubleBuffer(structureND.indices.linearSize) { value } - return DoubleTensor(shape, buffer) - } - - /** - * Returns a tensor filled with the scalar value `0.0`, with the shape defined by the variable argument [shape]. - * - * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value `0.0`, with the [shape] shape. - */ - public fun zeros(shape: ShapeND): DoubleTensor = full(0.0, shape) - - /** - * Returns a tensor filled with the scalar value `0.0`, with the same shape as a given array. - * - * @return tensor filled with the scalar value `0.0`, with the same shape as `input` tensor. - */ - public fun zeroesLike(structureND: StructureND<*>): DoubleTensor = fullLike(structureND, 0.0) - - /** - * Returns a tensor filled with the scalar value `1.0`, with the shape defined by the variable argument [shape]. - * - * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value `1.0`, with the [shape] shape. - */ - public fun ones(shape: ShapeND): DoubleTensor = full(1.0, shape) - - /** - * Returns a tensor filled with the scalar value `1.0`, with the same shape as a given array. - * - * @return tensor filled with the scalar value `1.0`, with the same shape as `input` tensor. - */ - public fun onesLike(structureND: StructureND<*>): DoubleTensor = fullLike(structureND, 1.0) - - /** - * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. - * - * @param n the number of rows and columns - * @return a 2-D tensor with ones on the diagonal and zeros elsewhere. - */ - public fun eye(n: Int): DoubleTensor { - val shape = ShapeND(n, n) - val buffer = DoubleBuffer(n * n) { 0.0 } - val res = DoubleTensor(shape, buffer) - for (i in 0 until n) { - res[intArrayOf(i, i)] = 1.0 - } - return res - } - - override fun Double.plus(arg: StructureND): DoubleTensor = arg.map { this@plus + it } - - override fun StructureND.plus(arg: Double): DoubleTensor = map { it + arg } - - override fun StructureND.plus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l + r } - - override fun Tensor.plusAssign(value: Double) { - mapInPlace { it + value } - } - - override fun Tensor.plusAssign(arg: StructureND) { - checkShapesCompatible(asDoubleTensor(), arg.asDoubleTensor()) - mapIndexedInPlace { index, value -> - value + arg[index] - } - } - - override fun Double.minus(arg: StructureND): DoubleTensor = arg.map { this@minus - it } - - override fun StructureND.minus(arg: Double): DoubleTensor = map { it - arg } - - override fun StructureND.minus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l - r } - - override fun Tensor.minusAssign(value: Double) { - mapInPlace { it - value } - } - - override fun Tensor.minusAssign(arg: StructureND) { - checkShapesCompatible(this, arg) - mapIndexedInPlace { index, value -> value - arg.getDouble(index) } - } - - override fun Double.times(arg: StructureND): DoubleTensor = arg.map { this@times * it } - - override fun StructureND.times(arg: Double): DoubleTensor = arg * asDoubleTensor() - - override fun StructureND.times(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l * r } - - override fun Tensor.timesAssign(value: Double) { - mapInPlace { it * value } - } - - override fun Tensor.timesAssign(arg: StructureND) { - checkShapesCompatible(this, arg) - mapIndexedInPlace { index, value -> value * arg[index] } - } - - override fun Double.div(arg: StructureND): DoubleTensor = arg.map { this@div / it } - - override fun StructureND.div(arg: Double): DoubleTensor = map { it / arg } - - override fun StructureND.div(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l / r } - - override fun Tensor.divAssign(value: Double) { - mapInPlace { it / value } - } - - override fun Tensor.divAssign(arg: StructureND) { - checkShapesCompatible(asDoubleTensor(), arg) - mapIndexedInPlace { index, value -> value / arg[index] } - } - - override fun StructureND.unaryMinus(): DoubleTensor = map { -it } - - override fun StructureND.transposed(i: Int, j: Int): Tensor { - val actualI = if (i >= 0) i else shape.size + i - val actualJ = if (j >= 0) j else shape.size + j - return asDoubleTensor().permute( - shape.transposed(actualI, actualJ) - ) { originIndex -> - originIndex.copyOf().apply { - val ith = get(actualI) - val jth = get(actualJ) - set(actualI, jth) - set(actualJ, ith) - } - } -// // TODO change strides instead of changing content -// val dt = asDoubleTensor() -// val ii = dt.minusIndex(i) -// val jj = dt.minusIndex(j) -// checkTranspose(dt.dimension, ii, jj) -// val n = dt.linearSize -// val resBuffer = DoubleArray(n) -// -// val resShape = dt.shape.copyOf() -// resShape[ii] = resShape[jj].also { resShape[jj] = resShape[ii] } -// -// val resTensor = DoubleTensor(resShape, resBuffer.asBuffer()) -// -// for (offset in 0 until n) { -// val oldMultiIndex = dt.indices.index(offset) -// val newMultiIndex = oldMultiIndex.copyOf() -// newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } -// -// val linearIndex = resTensor.indices.offset(newMultiIndex) -// resTensor.source[linearIndex] = dt.source[offset] -// } -// return resTensor - } - - override fun Tensor.view(shape: ShapeND): DoubleTensor { - checkView(asDoubleTensor(), shape) - return DoubleTensor(shape, asDoubleTensor().source) - } - - override fun Tensor.viewAs(other: StructureND): DoubleTensor = - view(other.shape) - - /** - * Broadcasting Matrix product of two tensors. - * - * The behavior depends on the dimensionality of the tensors as follows: - * 1. If both tensors are 1-dimensional, the dot product (scalar) is returned. - * - * 2. If both arguments are 2-dimensional, the matrix-matrix product is returned. - * - * 3. If the first argument is 1-dimensional and the second argument is 2-dimensional, - * a 1 is prepended to its dimension for the purpose of the matrix multiply. - * After the matrix multiply, depending on the implementation the prepended dimension might be removed. - * - * 4. If the first argument is 2-dimensional and the second argument is 1-dimensional, - * the matrix-vector product is returned. - * - * 5. If both arguments are at least 1-dimensional and at least one argument is N-dimensional (where N > 2), - * then a batched matrix multiply is returned. If the first argument is 1-dimensional, - * a 1 is prepended to its dimension for the purpose of the batched matrix multiply and removed after. - * If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix - * multiple and removed after. - * The non-matrix (i.e., batch) dimensions are broadcast (and thus must be broadcastable). - * For example, if `input` is a (j × 1 × n × n) tensor and `other` is a - * (k × n × n) tensor, out will be a (j × k × n × n) tensor. - * - * For more information: https://pytorch.org/docs/stable/generated/torch.matmul.html - * - * @param other tensor to be multiplied. - * @return a mathematical product of two tensors. - */ - public infix fun StructureND.matmul(other: StructureND): DoubleTensor { - if (shape.size == 1 && other.shape.size == 1) { - return DoubleTensor(ShapeND(1), DoubleBuffer(times(other).sum())) - } - - var penultimateDim = false - var lastDim = false - - //TODO do we need protective copy here? - var newThis: DoubleTensor = copyToTensor() - var newOther: DoubleTensor = other.copyToTensor() - - if (shape.size == 1) { - penultimateDim = true - newThis = newThis.view(ShapeND(1) + shape) - } - - if (other.shape.size == 1) { - lastDim = true - newOther = newOther.view(other.shape + intArrayOf(1)) - } - - val broadcastTensors = broadcastOuterTensors(newThis, newOther) - newThis = broadcastTensors[0] - newOther = broadcastTensors[1] - - val l = newThis.shape[newThis.shape.size - 2] - val m1 = newThis.shape[newThis.shape.size - 1] - val m2 = newOther.shape[newOther.shape.size - 2] - val n = newOther.shape[newOther.shape.size - 1] - check(m1 == m2) { - "Tensors dot operation dimension mismatch: ($l, $m1) x ($m2, $n)" - } - - val resShape = newThis.shape.slice(0..(newThis.shape.size - 2)) + intArrayOf(newOther.shape.last()) - val resSize = resShape.linearSize - val resTensor = DoubleTensor(resShape, DoubleArray(resSize).asBuffer()) - - val resMatrices = resTensor.matrices - val newThisMatrices = newThis.matrices - val newOtherMatrices = newOther.matrices - - for (i in resMatrices.indices) { - dotTo(newThisMatrices[i], newOtherMatrices[i], resMatrices[i], l, m1, n) - } -// -// for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { -// val (a, b) = ab -// dotTo(a, b, res, l, m1, n) -// } - - return if (penultimateDim) { - resTensor.view(resTensor.shape.first(resTensor.shape.size - 2) + ShapeND(resTensor.shape.last())) - } else if (lastDim) { - resTensor.view(resTensor.shape.first(resTensor.shape.size - 1)) - } else { - resTensor - } - } - - override fun StructureND.dot(other: StructureND): DoubleTensor { - return if (dimension in 0..2 && other.dimension in 0..2) this.matmul(other) - else error("Only vectors and matrices are allowed in non-broadcasting dot operation") - } - - override fun diagonalEmbedding( - diagonalEntries: StructureND, - offset: Int, - dim1: Int, - dim2: Int, - ): DoubleTensor { - val n = diagonalEntries.shape.size - val d1 = minusIndexFrom(n + 1, dim1) - val d2 = minusIndexFrom(n + 1, dim2) - - check(d1 != d2) { - "Diagonal dimensions cannot be identical $d1, $d2" - } - check(d1 <= n && d2 <= n) { - "Dimension out of range" - } - - var lessDim = d1 - var greaterDim = d2 - var realOffset = offset - if (lessDim > greaterDim) { - realOffset *= -1 - lessDim = greaterDim.also { greaterDim = lessDim } - } - - val resShape = diagonalEntries.shape.slice(0 until lessDim) + - intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + - diagonalEntries.shape.slice(lessDim until greaterDim - 1) + - intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + - diagonalEntries.shape.slice(greaterDim - 1 until n - 1) - val resTensor: DoubleTensor = zeros(resShape) - - for (i in 0 until diagonalEntries.indices.linearSize) { - val multiIndex = diagonalEntries.indices.index(i) - - var offset1 = 0 - var offset2 = abs(realOffset) - if (realOffset < 0) { - offset1 = offset2.also { offset2 = offset1 } - } - val diagonalMultiIndex = multiIndex.slice(0 until lessDim).toIntArray() + - intArrayOf(multiIndex[n - 1] + offset1) + - multiIndex.slice(lessDim until greaterDim - 1).toIntArray() + - intArrayOf(multiIndex[n - 1] + offset2) + - multiIndex.slice(greaterDim - 1 until n - 1).toIntArray() - - resTensor[diagonalMultiIndex] = diagonalEntries[multiIndex] - } - - return resTensor - } - - /** - * Compares element-wise two tensors with a specified precision. - * - * @param other the tensor to compare with `input` tensor. - * @param epsilon permissible error when comparing two Double values. - * @return true if two tensors have the same shape and elements, false otherwise. - */ - public fun Tensor.eq(other: Tensor, epsilon: Double): Boolean = - asDoubleTensor().eq(other) { x, y -> abs(x - y) < epsilon } - - /** - * Compares element-wise two tensors. - * Comparison of two Double values occurs with `1e-5` precision. - * - * @param other the tensor to compare with `input` tensor. - * @return true if two tensors have the same shape and elements, false otherwise. - */ - public infix fun Tensor.eq(other: Tensor): Boolean = eq(other, 1e-5) - - private fun Tensor.eq( - other: Tensor, - eqFunction: (Double, Double) -> Boolean, - ): Boolean { - //TODO optimize tensor conversion - checkShapesCompatible(asDoubleTensor(), other) - val n = asDoubleTensor().linearSize - if (n != other.asDoubleTensor().linearSize) { - return false - } - for (i in 0 until n) { - if (!eqFunction(asDoubleTensor().source[i], other.asDoubleTensor().source[i])) { - return false - } - } - return true - } - - /** - * Builds tensor from rows of the input tensor. - * - * @param indices the [IntArray] of 1-dimensional indices - * @return tensor with rows corresponding to row by [indices] - */ - public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { getTensor(it) }) - - - private inline fun StructureND.foldDimToDouble( - dim: Int, - keepDim: Boolean, - foldFunction: (DoubleArray) -> Double, - ): DoubleTensor { - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val resShape = if (keepDim) { - shape.first(dim) + intArrayOf(1) + shape.last(dimension - dim - 1) - } else { - shape.first(dim) + shape.last(dimension - dim - 1) - } - val resNumElements = resShape.linearSize - val init = foldFunction(DoubleArray(1) { 0.0 }) - val resTensor = DoubleTensor( - resShape, - DoubleBuffer(resNumElements) { init } - ) - val dt = asDoubleTensor() - for (index in resTensor.indices) { - val prefix = index.take(dim).toIntArray() - val suffix = index.takeLast(dimension - dim - 1).toIntArray() - resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> - dt[prefix + intArrayOf(i) + suffix] - }) - } - return resTensor - } - - private inline fun StructureND.foldDimToInt( - dim: Int, - keepDim: Boolean, - foldFunction: (DoubleArray) -> Int, - ): IntTensor { - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val resShape = if (keepDim) { - shape.first(dim) + intArrayOf(1) + shape.last(dimension - dim - 1) - } else { - shape.first(dim) + shape.last(dimension - dim - 1) - } - val resNumElements = resShape.linearSize - val init = foldFunction(DoubleArray(1) { 0.0 }) - val resTensor = IntTensor( - resShape, - IntBuffer(resNumElements) { init } - ) - for (index in resTensor.indices) { - val prefix = index.take(dim).toIntArray() - val suffix = index.takeLast(dimension - dim - 1).toIntArray() - resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> - asDoubleTensor()[prefix + intArrayOf(i) + suffix] - }) - } - return resTensor - } - - - override fun StructureND.sum(): Double = reduceElements { it.array.sum() } - - override fun StructureND.sum(dim: Int, keepDim: Boolean): DoubleTensor = - foldDimToDouble(dim, keepDim) { x -> x.sum() } - - override fun StructureND.min(): Double = reduceElements { it.array.min() } - - override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = - foldDimToDouble(dim, keepDim) { x -> x.minOrNull()!! } - - override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = foldDimToInt(dim, keepDim) { x -> - x.withIndex().minBy { it.value }.index - } - - override fun StructureND.max(): Double = reduceElements { it.array.max() } - - override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = - foldDimToDouble(dim, keepDim) { x -> x.maxOrNull()!! } - - - override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = - foldDimToInt(dim, keepDim) { x -> - x.withIndex().maxBy { it.value }.index - } - - - override fun mean(structureND: StructureND): Double = structureND.sum() / structureND.indices.linearSize - - override fun mean(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = - structureND.foldDimToDouble(dim, keepDim) { arr -> - check(dim < structureND.dimension) { "Dimension $dim out of range ${structureND.dimension}" } - arr.sum() / structureND.shape[dim] - } - - override fun std(structureND: StructureND): Double = structureND.reduceElements { arr -> - val mean = arr.array.sum() / structureND.indices.linearSize - sqrt(arr.array.sumOf { (it - mean) * (it - mean) } / (structureND.indices.linearSize - 1)) - } - - override fun std(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = - structureND.foldDimToDouble( - dim, - keepDim - ) { arr -> - check(dim < structureND.dimension) { "Dimension $dim out of range ${structureND.dimension}" } - val mean = arr.sum() / structureND.shape[dim] - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (structureND.shape[dim] - 1)) - } - - override fun variance(structureND: StructureND): Double = structureND.reduceElements { arr -> - val linearSize = structureND.indices.linearSize - val mean = arr.array.sum() / linearSize - arr.array.sumOf { (it - mean) * (it - mean) } / (linearSize - 1) - } - - override fun variance(structureND: StructureND, dim: Int, keepDim: Boolean): Tensor = - structureND.foldDimToDouble( - dim, - keepDim - ) { arr -> - check(dim < structureND.dimension) { "Dimension $dim out of range ${structureND.dimension}" } - val mean = arr.sum() / structureND.shape[dim] - arr.sumOf { (it - mean) * (it - mean) } / (structureND.shape[dim] - 1) - } - - - override fun exp(arg: StructureND): DoubleTensor = arg.map { this.exp(it) } - - override fun ln(arg: StructureND): DoubleTensor = arg.map { this.ln(it) } - - override fun sqrt(arg: StructureND): DoubleTensor = arg.map { this.sqrt(it) } - - override fun cos(arg: StructureND): DoubleTensor = arg.map { this.cos(it) } - - override fun acos(arg: StructureND): DoubleTensor = arg.map { this.acos(it) } - - override fun cosh(arg: StructureND): DoubleTensor = arg.map { this.cosh(it) } - - override fun acosh(arg: StructureND): DoubleTensor = arg.map { this.acosh(it) } - - override fun sin(arg: StructureND): DoubleTensor = arg.map { this.sin(it) } - - override fun asin(arg: StructureND): DoubleTensor = arg.map { this.asin(it) } - - override fun sinh(arg: StructureND): DoubleTensor = arg.map { this.sinh(it) } - - override fun asinh(arg: StructureND): DoubleTensor = arg.map { this.asinh(it) } - - override fun tan(arg: StructureND): DoubleTensor = arg.map { this.tan(it) } - - override fun atan(arg: StructureND): DoubleTensor = arg.map { this.atan(it) } - - override fun tanh(arg: StructureND): DoubleTensor = arg.map { this.tanh(it) } - - override fun atanh(arg: StructureND): DoubleTensor = arg.map { this.atanh(it) } - - override fun power(arg: StructureND, pow: Number): StructureND = if (pow is Int) { - arg.map { it.pow(pow) } - } else { - arg.map { it.pow(pow.toDouble()) } - } - - override fun ceil(arg: StructureND): DoubleTensor = arg.map { ceil(it) } - - override fun floor(structureND: StructureND): DoubleTensor = structureND.map { floor(it) } - - override fun StructureND.inv(): DoubleTensor = invLU(this, 1e-9) - - override fun StructureND.det(): DoubleTensor = detLU(this, 1e-9) - - override fun lu(structureND: StructureND): Triple = - lu(structureND, 1e-9) - - override fun cholesky(structureND: StructureND): DoubleTensor = cholesky(structureND, 1e-6) - - override fun qr(structureND: StructureND): Pair { - checkSquareMatrix(structureND.shape) - val qTensor = zeroesLike(structureND) - val rTensor = zeroesLike(structureND) - - //TODO replace with cycle - structureND.asDoubleTensor().matrixSequence() - .zip( - (qTensor.matrixSequence() - .zip(rTensor.matrixSequence())) - ).forEach { (matrix, qr) -> - val (q, r) = qr - qrHelper(matrix, q, r.asDoubleTensor2D()) - } - - return qTensor to rTensor - } - - override fun svd( - structureND: StructureND, - ): Triple, StructureND, StructureND> = - svd(structureND = structureND, epsilon = 1e-10) - - override fun symEig(structureND: StructureND): Pair = - symEigJacobi(structureND = structureND, maxIteration = 50, epsilon = 1e-15) - -} - -public val Double.Companion.tensorAlgebra: DoubleTensorAlgebra get() = DoubleTensorAlgebra -public val DoubleField.tensorAlgebra: DoubleTensorAlgebra get() = DoubleTensorAlgebra - - diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt deleted file mode 100644 index f028e2cbb..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.structures.* - -/** - * Default [BufferedTensor] implementation for [Int] values - */ -public class OffsetIntBuffer( - private val source: IntBuffer, - private val offset: Int, - override val size: Int, -) : MutableBuffer { - - init { - require(offset >= 0) { "Offset must be non-negative" } - require(size >= 0) { "Size must be non-negative" } - require(offset + size <= source.size) { "Maximum index must be inside source dimension" } - } - - override fun set(index: Int, value: Int) { - require(index in 0 until size) { "Index must be in [0, size)" } - source[index + offset] = value - } - - override fun get(index: Int): Int = source[index + offset] - - /** - * Copy only a part of buffer that belongs to this tensor - */ - override fun copy(): IntBuffer = source.array.copyOfRange(offset, offset + size).asBuffer() - - override fun iterator(): Iterator = iterator { - for (i in indices) { - yield(get(i)) - } - } - - override fun toString(): String = Buffer.toString(this) - - public fun view(addOffset: Int, newSize: Int = size - addOffset): OffsetIntBuffer = - OffsetIntBuffer(source, offset + addOffset, newSize) -} - -public fun OffsetIntBuffer.slice(range: IntRange): OffsetIntBuffer = view(range.first, range.last - range.first) - -/** - * Map only operable content of the offset buffer - */ -public inline fun OffsetIntBuffer.map(operation: (Int) -> Int): IntBuffer = - IntBuffer(size) { operation(get(it)) } - -public inline fun OffsetIntBuffer.zip( - other: OffsetIntBuffer, - operation: (l: Int, r: Int) -> Int, -): IntBuffer { - require(size == other.size) { "The sizes of zipped buffers must be the same" } - return IntBuffer(size) { operation(get(it), other[it]) } -} - -/** - * map in place - */ -public inline fun OffsetIntBuffer.mapInPlace(operation: (Int) -> Int) { - indices.forEach { set(it, operation(get(it))) } -} - -/** - * Default [BufferedTensor] implementation for [Int] values - */ -public class IntTensor( - shape: ShapeND, - override val source: OffsetIntBuffer, -) : BufferedTensor(shape) { - - init { - require(linearSize == source.size) { "Source buffer size must be equal tensor size" } - } - - public constructor(shape: ShapeND, buffer: IntBuffer) : this(shape, OffsetIntBuffer(buffer, 0, buffer.size)) - - @OptIn(PerformancePitfall::class) - override fun get(index: IntArray): Int = this.source[indices.offset(index)] - - @OptIn(PerformancePitfall::class) - override fun set(index: IntArray, value: Int) { - source[indices.offset(index)] = value - } -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt deleted file mode 100644 index d1cdc68d4..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - - -@file:OptIn(PerformancePitfall::class) - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.structures.* -import space.kscience.kmath.tensors.api.* -import space.kscience.kmath.tensors.core.internal.* -import kotlin.math.* - -/** - * Implementation of basic operations over double tensors and basic algebra operations on them. - */ -public open class IntTensorAlgebra : TensorAlgebra { - - public companion object : IntTensorAlgebra() - - - override val elementAlgebra: IntRing get() = IntRing - - - /** - * Applies the [transform] function to each element of the tensor and returns the resulting modified tensor. - * - * @param transform the function to be applied to each element of the tensor. - * @return the resulting tensor after applying the function. - */ - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun StructureND.map(transform: IntRing.(Int) -> Int): IntTensor { - val tensor = this.asIntTensor() - //TODO remove additional copy - val array = IntBuffer(tensor.source.size) { IntRing.transform(tensor.source[it]) } - return IntTensor( - tensor.shape, - array, - ) - } - - public inline fun Tensor.mapInPlace(operation: (Int) -> Int) { - if (this is IntTensor) { - source.mapInPlace(operation) - } else { - indices.forEach { set(it, operation(get(it))) } - } - } - - public inline fun Tensor.mapIndexedInPlace(operation: (IntArray, Int) -> Int) { - indices.forEach { set(it, operation(it, get(it))) } - } - - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun StructureND.mapIndexed(transform: IntRing.(index: IntArray, Int) -> Int): IntTensor { - val tensor = this.asIntTensor() - //TODO remove additional copy - val buffer = IntBuffer(tensor.source.size) { - IntRing.transform(tensor.indices.index(it), tensor.source[it]) - } - return IntTensor(tensor.shape, buffer) - } - - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun zip( - left: StructureND, - right: StructureND, - transform: IntRing.(Int, Int) -> Int, - ): IntTensor { - checkShapesCompatible(left, right) - - val leftTensor = left.asIntTensor() - val rightTensor = right.asIntTensor() - val buffer = IntBuffer(leftTensor.source.size) { - IntRing.transform(leftTensor.source[it], rightTensor.source[it]) - } - return IntTensor(leftTensor.shape, buffer) - } - - - public inline fun StructureND.reduceElements(transform: (IntBuffer) -> Int): Int = - transform(asIntTensor().source.copy()) - //TODO do we need protective copy? - - override fun StructureND.valueOrNull(): Int? { - val dt = asIntTensor() - return if (dt.shape contentEquals ShapeND(1)) dt.source[0] else null - } - - override fun StructureND.value(): Int = valueOrNull() - ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") - - /** - * Constructs a tensor with the specified shape and data. - * - * @param shape the desired shape for the tensor. - * @param array one-dimensional data array. - * @return tensor with the [shape] shape and [array] data. - */ - public fun fromArray(shape: ShapeND, array: IntArray): IntTensor { - checkNotEmptyShape(shape) - check(array.isNotEmpty()) { "Illegal empty buffer provided" } - check(array.size == shape.linearSize) { - "Inconsistent shape ${shape} for buffer of size ${array.size} provided" - } - return IntTensor(shape, array.asBuffer()) - } - - /** - * Constructs a tensor with the specified shape and initializer. - * - * @param shape the desired shape for the tensor. - * @param initializer mapping tensor indices to values. - * @return tensor with the [shape] shape and data generated by the [initializer]. - */ - override fun structureND(shape: ShapeND, initializer: IntRing.(IntArray) -> Int): IntTensor = fromArray( - shape, - RowStrides(shape).asSequence().map { IntRing.initializer(it) }.toMutableList().toIntArray() - ) - - override fun Tensor.getTensor(i: Int): IntTensor { - val dt = asIntTensor() - val lastShape = shape.last(shape.size - 1) - val newShape = if (lastShape.isNotEmpty()) lastShape else ShapeND(1) - return IntTensor(newShape, dt.source.view(newShape.linearSize * i)) - } - - /** - * Creates a tensor of a given shape and fills all elements with a given value. - * - * @param value the value to fill the output tensor with. - * @param shape array of integers defining the shape of the output tensor. - * @return tensor with the [shape] shape and filled with [value]. - */ - public fun full(value: Int, shape: ShapeND): IntTensor { - checkNotEmptyShape(shape) - val buffer = IntBuffer(shape.linearSize) { value } - return IntTensor(shape, buffer) - } - - /** - * Returns a tensor with the same shape as `input` filled with [value]. - * - * @param value the value to fill the output tensor with. - * @return tensor with the `input` tensor shape and filled with [value]. - */ - public fun fullLike(structureND: StructureND<*>, value: Int): IntTensor { - val shape = structureND.shape - val buffer = IntBuffer(structureND.indices.linearSize) { value } - return IntTensor(shape, buffer) - } - - /** - * Returns a tensor filled with the scalar value `0`, with the shape defined by the variable argument [shape]. - * - * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value `0`, with the [shape] shape. - */ - public fun zeros(shape: ShapeND): IntTensor = full(0, shape) - - /** - * Returns a tensor filled with the scalar value `0`, with the same shape as a given array. - * - * @return tensor filled with the scalar value `0`, with the same shape as `input` tensor. - */ - public fun zeroesLike(structureND: StructureND): IntTensor = fullLike(structureND.asIntTensor(), 0) - - /** - * Returns a tensor filled with the scalar value `1`, with the shape defined by the variable argument [shape]. - * - * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value `1`, with the [shape] shape. - */ - public fun ones(shape: ShapeND): IntTensor = full(1, shape) - - /** - * Returns a tensor filled with the scalar value `1`, with the same shape as a given array. - * - * @return tensor filled with the scalar value `1`, with the same shape as `input` tensor. - */ - public fun onesLike(structureND: Tensor<*>): IntTensor = fullLike(structureND, 1) - - /** - * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. - * - * @param n the number of rows and columns - * @return a 2-D tensor with ones on the diagonal and zeros elsewhere. - */ - public fun eye(n: Int): IntTensor { - val shape = ShapeND(n, n) - val buffer = IntBuffer(n * n) { 0 } - val res = IntTensor(shape, buffer) - for (i in 0 until n) { - res[intArrayOf(i, i)] = 1 - } - return res - } - - override fun Int.plus(arg: StructureND): IntTensor = arg.map { this@plus + it } - - override fun StructureND.plus(arg: Int): IntTensor = map { it + arg } - - override fun StructureND.plus(arg: StructureND): IntTensor = zip(this, arg) { l, r -> l + r } - - override fun Tensor.plusAssign(value: Int) { - mapInPlace { it + value } - } - - override fun Tensor.plusAssign(arg: StructureND) { - checkShapesCompatible(asIntTensor(), arg.asIntTensor()) - mapIndexedInPlace { index, value -> - value + arg[index] - } - } - - override fun Int.minus(arg: StructureND): IntTensor = arg.map { this@minus - it } - - override fun StructureND.minus(arg: Int): IntTensor = map { it - arg } - - override fun StructureND.minus(arg: StructureND): IntTensor = zip(this, arg) { l, r -> l - r } - - override fun Tensor.minusAssign(value: Int) { - mapInPlace { it - value } - } - - override fun Tensor.minusAssign(arg: StructureND) { - checkShapesCompatible(this, arg) - mapIndexedInPlace { index, value -> value - arg[index] } - } - - override fun Int.times(arg: StructureND): IntTensor = arg.map { this@times * it } - - override fun StructureND.times(arg: Int): IntTensor = arg * asIntTensor() - - override fun StructureND.times(arg: StructureND): IntTensor = zip(this, arg) { l, r -> l * r } - - override fun Tensor.timesAssign(value: Int) { - mapInPlace { it * value } - } - - override fun Tensor.timesAssign(arg: StructureND) { - checkShapesCompatible(this, arg) - mapIndexedInPlace { index, value -> value * arg[index] } - } - - override fun StructureND.unaryMinus(): IntTensor = map { -it } - - override fun StructureND.transposed(i: Int, j: Int): Tensor { - val actualI = if (i >= 0) i else shape.size + i - val actualJ = if(j>=0) j else shape.size + j - return asIntTensor().permute( - shape.transposed(actualI, actualJ) - ) { originIndex -> - originIndex.copyOf().apply { - val ith = get(actualI) - val jth = get(actualJ) - set(actualI, jth) - set(actualJ, ith) - } - } -// // TODO change strides instead of changing content -// val dt = asIntTensor() -// val ii = dt.minusIndex(i) -// val jj = dt.minusIndex(j) -// checkTranspose(dt.dimension, ii, jj) -// val n = dt.linearSize -// val resBuffer = IntArray(n) -// -// val resShape = dt.shape.toArray() -// resShape[ii] = resShape[jj].also { resShape[jj] = resShape[ii] } -// -// val resTensor = IntTensor(Shape(resShape), resBuffer.asBuffer()) -// -// for (offset in 0 until n) { -// val oldMultiIndex = dt.indices.index(offset) -// val newMultiIndex = oldMultiIndex.copyOf() -// newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } -// -// val linearIndex = resTensor.indices.offset(newMultiIndex) -// resTensor.source[linearIndex] = dt.source[offset] -// } -// return resTensor - } - - override fun Tensor.view(shape: ShapeND): IntTensor { - checkView(asIntTensor(), shape) - return IntTensor(shape, asIntTensor().source) - } - - override fun Tensor.viewAs(other: StructureND): IntTensor = - view(other.shape) - - override fun StructureND.dot(other: StructureND): IntTensor { - TODO("not implemented for integers") - } - - override fun diagonalEmbedding( - diagonalEntries: StructureND, - offset: Int, - dim1: Int, - dim2: Int, - ): IntTensor { - val n = diagonalEntries.shape.size - val d1 = minusIndexFrom(n + 1, dim1) - val d2 = minusIndexFrom(n + 1, dim2) - - check(d1 != d2) { - "Diagonal dimensions cannot be identical $d1, $d2" - } - check(d1 <= n && d2 <= n) { - "Dimension out of range" - } - - var lessDim = d1 - var greaterDim = d2 - var realOffset = offset - if (lessDim > greaterDim) { - realOffset *= -1 - lessDim = greaterDim.also { greaterDim = lessDim } - } - - val resShape = diagonalEntries.shape.slice(0 until lessDim) + - intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + - diagonalEntries.shape.slice(lessDim until greaterDim - 1) + - intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + - diagonalEntries.shape.slice(greaterDim - 1 until n - 1) - val resTensor = zeros(resShape) - - for (i in 0 until diagonalEntries.asIntTensor().linearSize) { - val multiIndex = diagonalEntries.asIntTensor().indices.index(i) - - var offset1 = 0 - var offset2 = abs(realOffset) - if (realOffset < 0) { - offset1 = offset2.also { offset2 = offset1 } - } - val diagonalMultiIndex = multiIndex.slice(0 until lessDim).toIntArray() + - intArrayOf(multiIndex[n - 1] + offset1) + - multiIndex.slice(lessDim until greaterDim - 1).toIntArray() + - intArrayOf(multiIndex[n - 1] + offset2) + - multiIndex.slice(greaterDim - 1 until n - 1).toIntArray() - - resTensor[diagonalMultiIndex] = diagonalEntries[multiIndex] - } - - return resTensor.asIntTensor() - } - - /** - * Compares element-wise two int tensors - * - * @param other the tensor to compare with `input` tensor. - * @param epsilon permissible error when comparing two Int values. - * @return true if two tensors have the same shape and elements, false otherwise. - */ - public fun Tensor.eq(other: Tensor): Boolean = - asIntTensor().eq(other) { x, y -> x == y } - - private fun Tensor.eq( - other: Tensor, - eqFunction: (Int, Int) -> Boolean, - ): Boolean { - checkShapesCompatible(asIntTensor(), other) - val n = asIntTensor().linearSize - if (n != other.asIntTensor().linearSize) { - return false - } - for (i in 0 until n) { - if (!eqFunction(asIntTensor().source[i], other.asIntTensor().source[i])) { - return false - } - } - return true - } - - /** - * Concatenates a sequence of tensors with equal shapes along the first dimension. - * - * @param tensors the [List] of tensors with same shapes to concatenate - * @return tensor with concatenation result - */ - public fun stack(tensors: List>): IntTensor { - check(tensors.isNotEmpty()) { "List must have at least 1 element" } - val shape = tensors[0].shape - check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } - val resShape = ShapeND(tensors.size) + shape -// val resBuffer: List = tensors.flatMap { -// it.asIntTensor().source.array.drop(it.asIntTensor().bufferStart) -// .take(it.asIntTensor().linearSize) -// } - val resBuffer = tensors.map { it.asIntTensor().source }.concat() - return IntTensor(resShape, resBuffer) - } - - /** - * Builds tensor from rows of the input tensor. - * - * @param indices the [IntArray] of 1-dimensional indices - * @return tensor with rows corresponding to row by [indices] - */ - public fun Tensor.rowsByIndices(indices: IntArray): IntTensor = stack(indices.map { getTensor(it) }) - - private inline fun StructureND.foldDimToInt( - dim: Int, - keepDim: Boolean, - foldFunction: (IntArray) -> Int, - ): IntTensor { - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val resShape = if (keepDim) { - shape.first(dim) + intArrayOf(1) + shape.last(dimension - dim - 1) - } else { - shape.first(dim) + shape.last(dimension - dim - 1) - } - val resNumElements = resShape.linearSize - val init = foldFunction(IntArray(1) { 0 }) - val resTensor = IntTensor( - resShape, - IntBuffer(resNumElements) { init } - ) - for (index in resTensor.indices) { - val prefix = index.take(dim).toIntArray() - val suffix = index.takeLast(dimension - dim - 1).toIntArray() - resTensor[index] = foldFunction(IntArray(shape[dim]) { i -> - asIntTensor()[prefix + intArrayOf(i) + suffix] - }) - } - return resTensor - } - - - override fun StructureND.sum(): Int = reduceElements { it.array.sum() } - - override fun StructureND.sum(dim: Int, keepDim: Boolean): IntTensor = - foldDimToInt(dim, keepDim) { x -> x.sum() } - - override fun StructureND.min(): Int = reduceElements { it.array.min() } - - override fun StructureND.min(dim: Int, keepDim: Boolean): IntTensor = - foldDimToInt(dim, keepDim) { x -> x.minOrNull()!! } - - override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = foldDimToInt(dim, keepDim) { x -> - x.withIndex().minBy { it.value }.index - } - - override fun StructureND.max(): Int = reduceElements { it.array.max() } - - override fun StructureND.max(dim: Int, keepDim: Boolean): IntTensor = - foldDimToInt(dim, keepDim) { x -> x.max() } - - - override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = - foldDimToInt(dim, keepDim) { x -> - x.withIndex().maxBy { it.value }.index - } - - public fun StructureND.mean(): Double = sum().toDouble() / indices.linearSize -} - -public val Int.Companion.tensorAlgebra: IntTensorAlgebra get() = IntTensorAlgebra -public val IntRing.tensorAlgebra: IntTensorAlgebra get() = IntTensorAlgebra - - diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt deleted file mode 100644 index 1e87e6620..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.UnsafeKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.tensors.core.DoubleTensor -import kotlin.math.max - -internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { - for (linearIndex in 0 until linearSize) { - val totalMultiIndex = resTensor.indices.index(linearIndex) - val curMultiIndex = tensor.shape.toArray() - - val offset = totalMultiIndex.size - curMultiIndex.size - - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i + offset] - } else { - curMultiIndex[i] = 0 - } - } - - val curLinearIndex = tensor.indices.offset(curMultiIndex) - resTensor.source[linearIndex] = - tensor.source[curLinearIndex] - } -} - -internal fun broadcastShapes(shapes: List): ShapeND { - var totalDim = 0 - for (shape in shapes) { - totalDim = max(totalDim, shape.size) - } - - val totalShape = IntArray(totalDim) { 0 } - for (shape in shapes) { - for (i in shape.indices) { - val curDim = shape[i] - val offset = totalDim - shape.size - totalShape[i + offset] = max(totalShape[i + offset], curDim) - } - } - - for (shape in shapes) { - for (i in shape.indices) { - val curDim = shape[i] - val offset = totalDim - shape.size - check(curDim == 1 || totalShape[i + offset] == curDim) { - "Shapes are not compatible and cannot be broadcast" - } - } - } - - return ShapeND(totalShape) -} - -internal fun broadcastTo(tensor: DoubleTensor, newShape: ShapeND): DoubleTensor { - require(tensor.shape.size <= newShape.size) { - "Tensor is not compatible with the new shape" - } - - val n = newShape.linearSize - val resTensor = DoubleTensor(newShape, DoubleArray(n).asBuffer()) - - for (i in tensor.shape.indices) { - val curDim = tensor.shape[i] - val offset = newShape.size - tensor.shape.size - check(curDim == 1 || newShape[i + offset] == curDim) { - "Tensor is not compatible with the new shape and cannot be broadcast" - } - } - - multiIndexBroadCasting(tensor, resTensor, n) - return resTensor -} - -internal fun broadcastTensors(vararg tensors: DoubleTensor): List { - val totalShape = broadcastShapes(tensors.map { it.shape }) - val n = totalShape.linearSize - - return tensors.map { tensor -> - val resTensor = DoubleTensor(totalShape, DoubleArray(n).asBuffer()) - multiIndexBroadCasting(tensor, resTensor, n) - resTensor - } -} - -internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List { - val onlyTwoDims = tensors.asSequence().onEach { - require(it.shape.size >= 2) { - "Tensors must have at least 2 dimensions" - } - }.any { it.shape.size != 2 } - - if (!onlyTwoDims) { - return tensors.asList() - } - - val totalShape = broadcastShapes(tensors.map { it.shape.slice(0..it.shape.size - 3) }) - val n = totalShape.linearSize - - return buildList { - for (tensor in tensors) { - val matrixShape = tensor.shape.slice(tensor.shape.size - 2 until tensor.shape.size) - val matrixSize = matrixShape[0] * matrixShape[1] - val matrix = DoubleTensor(matrixShape, DoubleArray(matrixSize).asBuffer()) - - val outerTensor = DoubleTensor(totalShape, DoubleArray(n).asBuffer()) - val resTensor = DoubleTensor(totalShape + matrixShape, DoubleArray(n * matrixSize).asBuffer()) - - for (linearIndex in 0 until n) { - val totalMultiIndex = outerTensor.indices.index(linearIndex) - @OptIn(UnsafeKMathAPI::class) - var curMultiIndex = tensor.shape.slice(0..tensor.shape.size - 3).asArray() - curMultiIndex = IntArray(totalMultiIndex.size - curMultiIndex.size) { 1 } + curMultiIndex - - val newTensor = DoubleTensor(ShapeND(curMultiIndex) + matrixShape, tensor.source) - - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i] - } else { - curMultiIndex[i] = 0 - } - } - - for (i in 0 until matrixSize) { - val curLinearIndex = newTensor.indices.offset( - curMultiIndex + - matrix.indices.index(i) - ) - val newLinearIndex = resTensor.indices.offset( - totalMultiIndex + - matrix.indices.index(i) - ) - - resTensor.source[newLinearIndex] = - newTensor.source[curLinearIndex] - } - } - add(resTensor) - } - } -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt deleted file mode 100644 index f384ed462..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.contentEquals -import space.kscience.kmath.nd.linearSize -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.asDoubleTensor -import space.kscience.kmath.tensors.core.detLU - - -internal fun checkNotEmptyShape(shape: ShapeND) = - check(shape.size > 0) { - "Illegal empty shape provided" - } - -internal fun checkEmptyDoubleBuffer(buffer: DoubleArray) = check(buffer.isNotEmpty()) { - "Illegal empty buffer provided" -} - -internal fun checkBufferShapeConsistency(shape: ShapeND, buffer: DoubleArray) = - check(buffer.size == shape.linearSize) { - "Inconsistent shape $shape for buffer of size ${buffer.size} provided" - } - -@PublishedApi -internal fun checkShapesCompatible(a: StructureND, b: StructureND): Unit = - check(a.shape contentEquals b.shape) { - "Incompatible shapes ${a.shape} and ${b.shape} " - } - -internal fun checkTranspose(dim: Int, i: Int, j: Int) = - check((i < dim) and (j < dim)) { - "Cannot transpose $i to $j for a tensor of dim $dim" - } - -internal fun checkView(a: Tensor, shape: ShapeND) = - check(a.shape.linearSize == shape.linearSize) - -internal fun checkSquareMatrix(shape: ShapeND) { - val n = shape.size - check(n >= 2) { - "Expected tensor with 2 or more dimensions, got size $n instead" - } - check(shape[n - 1] == shape[n - 2]) { - "Tensor must be batches of square matrices, but they are ${shape[n - 1]} by ${shape[n - 1]} matrices" - } -} - -internal fun DoubleTensorAlgebra.checkSymmetric( - tensor: Tensor, epsilon: Double = 1e-6, -) = check(tensor.eq(tensor.transposed(), epsilon)) { - "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" -} - -internal fun DoubleTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor, epsilon: Double = 1e-6) { - checkSymmetric(tensor, epsilon) - for (mat in tensor.matrixSequence()) - check(detLU(mat.asDoubleTensor()).value() > 0.0) { - "Tensor contains matrices which are not positive definite ${detLU(mat.asDoubleTensor()).value()}" - } -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt deleted file mode 100644 index a293c8da3..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.nd.* -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.indices -import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.eye -import space.kscience.kmath.tensors.core.BufferedTensor -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.OffsetDoubleBuffer -import space.kscience.kmath.tensors.core.copyToTensor -import kotlin.math.abs -import kotlin.math.max -import kotlin.math.sqrt - - -internal fun MutableStructure2D.jacobiHelper( - maxIteration: Int, - epsilon: Double, -): Pair> { - val n = rowNum - val A_ = copyToTensor() - val V = eye(n) - val D = DoubleBuffer(n) { get(it, it) } - val B = DoubleBuffer(n) { get(it, it) } - val Z = DoubleBuffer(n) { 0.0 } - - // assume that buffered tensor is square matrix - operator fun DoubleTensor.get(i: Int, j: Int): Double { - return source[i * shape[0] + j] - } - - operator fun BufferedTensor.set(i: Int, j: Int, value: Double) { - source[i * shape[0] + j] = value - } - - fun maxOffDiagonal(matrix: DoubleTensor): Double { - var maxOffDiagonalElement = 0.0 - for (i in 0 until n - 1) { - for (j in i + 1 until n) { - maxOffDiagonalElement = max(maxOffDiagonalElement, abs(matrix[i, j])) - } - } - return maxOffDiagonalElement - } - - fun rotate(a: DoubleTensor, s: Double, tau: Double, i: Int, j: Int, k: Int, l: Int) { - val g = a[i, j] - val h = a[k, l] - a[i, j] = g - s * (h + g * tau) - a[k, l] = h + s * (g - h * tau) - } - - fun jacobiIteration( - a: DoubleTensor, - v: DoubleTensor, - d: DoubleBuffer, - z: DoubleBuffer, - ) { - for (ip in 0 until n - 1) { - for (iq in ip + 1 until n) { - val g = 100.0 * abs(a[ip, iq]) - - if (g <= epsilon * abs(d[ip]) && g <= epsilon * abs(d[iq])) { - a[ip, iq] = 0.0 - continue - } - - var h = d[iq] - d[ip] - val t = when { - g <= epsilon * abs(h) -> (a[ip, iq]) / h - else -> { - val theta = 0.5 * h / (a[ip, iq]) - val denominator = abs(theta) + sqrt(1.0 + theta * theta) - if (theta < 0.0) -1.0 / denominator else 1.0 / denominator - } - } - - val c = 1.0 / sqrt(1 + t * t) - val s = t * c - val tau = s / (1.0 + c) - h = t * a[ip, iq] - z[ip] -= h - z[iq] += h - d[ip] -= h - d[iq] += h - a[ip, iq] = 0.0 - - for (j in 0 until ip) { - rotate(a, s, tau, j, ip, j, iq) - } - for (j in (ip + 1) until iq) { - rotate(a, s, tau, ip, j, j, iq) - } - for (j in (iq + 1) until n) { - rotate(a, s, tau, ip, j, iq, j) - } - for (j in 0 until n) { - rotate(v, s, tau, j, ip, j, iq) - } - } - } - } - - fun updateDiagonal( - d: DoubleBuffer, - z: DoubleBuffer, - b: DoubleBuffer, - ) { - for (ip in 0 until d.size) { - b[ip] += z[ip] - d[ip] = b[ip] - z[ip] = 0.0 - } - } - - var sm = maxOffDiagonal(A_) - for (iteration in 0 until maxIteration) { - if (sm < epsilon) { - break - } - - jacobiIteration(A_, V, D, Z) - updateDiagonal(D, Z, B) - sm = maxOffDiagonal(A_) - } - - // TODO sort eigenvalues - return D to V.as2D() -} - -/** - * Concatenate a list of arrays - */ -internal fun List.concat(): DoubleBuffer { - val array = DoubleArray(sumOf { it.size }) - var pointer = 0 - while (pointer < array.size) { - for (bufferIndex in indices) { - val buffer = get(bufferIndex) - for (innerIndex in buffer.indices) { - array[pointer] = buffer[innerIndex] - pointer++ - } - } - } - return array.asBuffer() -} - -internal val DoubleTensor.vectors: List - get() { - val n = shape.size - val vectorOffset = shape[n - 1] - val vectorShape = ShapeND(shape.last()) - - return List(linearSize / vectorOffset) { index -> - val offset = index * vectorOffset - DoubleTensor(vectorShape, source.view(offset, vectorShape.first())) - } - } - - -internal fun DoubleTensor.vectorSequence(): Sequence = vectors.asSequence() - - -internal val DoubleTensor.matrices: List - get() { - val n = shape.size - check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } - val matrixOffset = shape[n - 1] * shape[n - 2] - val matrixShape = ShapeND(shape[n - 2], shape[n - 1]) - - val size = matrixShape.linearSize - - return List(linearSize / matrixOffset) { index -> - val offset = index * matrixOffset - DoubleTensor(matrixShape, source.view(offset, size)) - } - } - -internal fun DoubleTensor.matrixSequence(): Sequence = matrices.asSequence() \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt deleted file mode 100644 index 35f0bf324..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.first -import space.kscience.kmath.nd.last -import space.kscience.kmath.operations.asSequence -import space.kscience.kmath.structures.IntBuffer -import space.kscience.kmath.structures.VirtualBuffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.indices -import space.kscience.kmath.tensors.core.IntTensor -import space.kscience.kmath.tensors.core.OffsetIntBuffer - -/** - * Concatenate a list of arrays - */ -internal fun List.concat(): IntBuffer { - val array = IntArray(sumOf { it.size }) - var pointer = 0 - while (pointer < array.size) { - for (bufferIndex in indices) { - val buffer = get(bufferIndex) - for (innerIndex in buffer.indices) { - array[pointer] = buffer[innerIndex] - pointer++ - } - } - } - return array.asBuffer() -} - - -internal fun IntTensor.vectors(): VirtualBuffer { - val n = shape.size - val vectorOffset = shape[n - 1] - val vectorShape = shape.last(1) - - return VirtualBuffer(linearSize / vectorOffset) { index -> - val offset = index * vectorOffset - IntTensor(vectorShape, source.view(offset, vectorShape.first())) - } -} - - -internal fun IntTensor.vectorSequence(): Sequence = vectors().asSequence() - - -internal val IntTensor.matrices: VirtualBuffer - get(){ - val n = shape.size - check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } - val matrixOffset = shape[n - 1] * shape[n - 2] - val matrixShape = ShapeND(shape[n - 2], shape[n - 1]) - - return VirtualBuffer(linearSize / matrixOffset) { index -> - val offset = index * matrixOffset - IntTensor(matrixShape, source.view(offset)) - } - } - -internal fun IntTensor.matrixSequence(): Sequence = matrices.asSequence() \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt deleted file mode 100644 index cf3697e76..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.IntBuffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.indices -import space.kscience.kmath.tensors.core.* -import kotlin.math.abs -import kotlin.math.min -import kotlin.math.sqrt - -internal fun dotTo( - a: BufferedTensor, - b: BufferedTensor, - res: BufferedTensor, - l: Int, m: Int, n: Int, -) { - val aBuffer = a.source - val bBuffer = b.source - val resBuffer = res.source - - for (i in 0 until l) { - for (j in 0 until n) { - var curr = 0.0 - for (k in 0 until m) { - curr += aBuffer[i * m + k] * bBuffer[k * n + j] - } - resBuffer[i * n + j] = curr - } - } -} - -internal fun luHelper( - lu: MutableStructure2D, - pivots: MutableStructure1D, - epsilon: Double, -): Boolean { - - val m = lu.rowNum - - for (row in 0..m) pivots[row] = row - - for (i in 0 until m) { - var maxVal = 0.0 - var maxInd = i - - for (k in i until m) { - val absA = abs(lu[k, i]) - if (absA > maxVal) { - maxVal = absA - maxInd = k - } - } - - if (abs(maxVal) < epsilon) - return true // matrix is singular - - if (maxInd != i) { - - val j = pivots[i] - pivots[i] = pivots[maxInd] - pivots[maxInd] = j - - for (k in 0 until m) { - val tmp = lu[i, k] - lu[i, k] = lu[maxInd, k] - lu[maxInd, k] = tmp - } - - pivots[m] += 1 - - } - - for (j in i + 1 until m) { - lu[j, i] /= lu[i, i] - for (k in i + 1 until m) { - lu[j, k] -= lu[j, i] * lu[i, k] - } - } - } - return false -} - -internal fun StructureND.setUpPivots(): IntTensor { - val n = this.shape.size - val m = this.shape.last() - val pivotsShape = IntArray(n - 1) { i -> this.shape[i] } - pivotsShape[n - 2] = m + 1 - - return IntTensor( - ShapeND(pivotsShape), - IntBuffer(pivotsShape.reduce(Int::times)) { 0 } - ) -} - -internal fun DoubleTensorAlgebra.computeLU( - tensor: StructureND, - epsilon: Double, -): Pair? { - - checkSquareMatrix(tensor.shape) - val luTensor = tensor.copyToTensor() - val pivotsTensor = tensor.setUpPivots() - - for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) - if (luHelper(lu.asDoubleTensor2D(), pivots.as1D(), epsilon)) - return null - - return Pair(luTensor, pivotsTensor) -} - -internal fun pivInit( - p: MutableStructure2D, - pivot: MutableStructure1D, - n: Int, -) { - for (i in 0 until n) { - p[i, pivot[i]] = 1.0 - } -} - -internal fun luPivotHelper( - l: MutableStructure2D, - u: MutableStructure2D, - lu: MutableStructure2D, - n: Int, -) { - for (i in 0 until n) { - for (j in 0 until n) { - if (i == j) { - l[i, j] = 1.0 - } - if (j < i) { - l[i, j] = lu[i, j] - } - if (j >= i) { - u[i, j] = lu[i, j] - } - } - } -} - -internal fun choleskyHelper( - a: MutableStructure2D, - l: MutableStructure2D, - n: Int, -) { - for (i in 0 until n) { - for (j in 0 until i) { - var h = a[i, j] - for (k in 0 until j) { - h -= l[i, k] * l[j, k] - } - l[i, j] = h / l[j, j] - } - var h = a[i, i] - for (j in 0 until i) { - h -= l[i, j] * l[i, j] - } - l[i, i] = sqrt(h) - } -} - -internal fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructure1D): Double { - if (lu[0, 0] == 0.0) { - return 0.0 - } - val m = lu.shape[0] - val sign = if ((pivots[m] - m) % 2 == 0) 1.0 else -1.0 - return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } -} - -internal fun luMatrixInv( - lu: MutableStructure2D, - pivots: MutableStructure1D, - invMatrix: MutableStructure2D, -) { - val m = lu.shape[0] - - for (j in 0 until m) { - for (i in 0 until m) { - if (pivots[i] == j) { - invMatrix[i, j] = 1.0 - } - - for (k in 0 until i) { - invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] - } - } - - for (i in m - 1 downTo 0) { - for (k in i + 1 until m) { - invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] - } - invMatrix[i, j] /= lu[i, i] - } - } -} - -internal fun DoubleTensorAlgebra.qrHelper( - matrix: DoubleTensor, - q: DoubleTensor, - r: MutableStructure2D, -) { - checkSquareMatrix(matrix.shape) - val n = matrix.shape[0] - val qM = q.asDoubleTensor2D() - val matrixT = matrix.transposed(0, 1) - val qT = q.transposed(0, 1) - - for (j in 0 until n) { - val v = matrixT.getTensor(j) - val vv = v.asDoubleBuffer() - if (j > 0) { - for (i in 0 until j) { - r[i, j] = (qT.getTensor(i) dot matrixT.getTensor(j)).value() - for (k in 0 until n) { - val qTi = qT.getTensor(i).asDoubleBuffer() - vv[k] = vv[k] - r[i, j] * qTi[k] - } - } - } - r[j, j] = DoubleTensorAlgebra { sqrt((v dot v)).value() } - for (i in 0 until n) { - qM[i, j] = vv[i] / r[j, j] - } - } -} - -internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10): DoubleTensor { - val (n, m) = a.shape - var v: DoubleTensor - val b: DoubleTensor - if (n > m) { - b = a.transposed(0, 1).dot(a) - v = DoubleTensor(ShapeND(m), DoubleBuffer.randomUnitVector(m, 0)) - } else { - b = a.dot(a.transposed(0, 1)) - v = DoubleTensor(ShapeND(n), DoubleBuffer.randomUnitVector(n, 0)) - } - - var lastV: DoubleTensor - while (true) { - lastV = v - v = b.dot(lastV) - val norm = DoubleTensorAlgebra { sqrt((v dot v)).value() } - v = v.times(1.0 / norm) - if (abs(v.dot(lastV).value()) > 1 - epsilon) { - return v - } - } -} - -internal fun DoubleTensorAlgebra.svdHelper( - matrix: DoubleTensor, - USV: Triple, BufferedTensor, BufferedTensor>, - m: Int, n: Int, epsilon: Double, -) { - val res = ArrayList>(0) - val (matrixU, matrixS, matrixV) = USV - - for (k in 0 until min(n, m)) { - var a = matrix.copyToTensor() - for ((singularValue, u, v) in res.slice(0 until k)) { - val outerProduct = DoubleArray(u.shape[0] * v.shape[0]) - for (i in 0 until u.shape[0]) { - for (j in 0 until v.shape[0]) { - outerProduct[i * v.shape[0] + j] = u.getTensor(i).value() * v.getTensor(j).value() - } - } - a = a - singularValue.times(DoubleTensor(ShapeND(u.shape[0], v.shape[0]), outerProduct.asBuffer())) - } - var v: DoubleTensor - var u: DoubleTensor - var norm: Double - if (n > m) { - v = svd1d(a, epsilon) - u = matrix.dot(v) - norm = DoubleTensorAlgebra { sqrt((u dot u)).value() } - u = u.times(1.0 / norm) - } else { - u = svd1d(a, epsilon) - v = matrix.transposed(0, 1).dot(u) - norm = DoubleTensorAlgebra { sqrt((v dot v)).value() } - v = v.times(1.0 / norm) - } - - res.add(Triple(norm, u, v)) - } - - val s = res.map { it.first }.toDoubleArray() - val uBuffer = res.map { it.second.source }.concat() - val vBuffer = res.map { it.third.source }.concat() - for (i in uBuffer.indices) { - matrixU.source[i] = uBuffer[i] - } - for (i in s.indices) { - matrixS.source[i] = s[i] - } - for (i in vBuffer.indices) { - matrixV.source[i] = vBuffer[i] - } -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt deleted file mode 100644 index 2709ac474..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.asList -import space.kscience.kmath.nd.last -import space.kscience.kmath.operations.DoubleBufferOps.Companion.map -import space.kscience.kmath.random.RandomGenerator -import space.kscience.kmath.samplers.GaussianSampler -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.tensors.core.BufferedTensor -import space.kscience.kmath.tensors.core.DoubleTensor -import kotlin.math.* - -internal fun DoubleBuffer.Companion.randomNormals(n: Int, seed: Long): DoubleBuffer { - val distribution = GaussianSampler(0.0, 1.0) - val generator = RandomGenerator.default(seed) - return distribution.sample(generator).nextBufferBlocking(n) -} - -internal fun DoubleBuffer.Companion.randomUnitVector(n: Int, seed: Long): DoubleBuffer { - val unnorm: DoubleBuffer = randomNormals(n, seed) - val norm = sqrt(unnorm.array.sumOf { it * it }) - return unnorm.map { it / norm } -} - -internal fun minusIndexFrom(n: Int, i: Int): Int = if (i >= 0) i else { - val ii = n + i - check(ii >= 0) { - "Out of bound index $i for tensor of dim $n" - } - ii -} - -internal fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.dimension, i) - -internal fun format(value: Double, digits: Int = 4): String = buildString { - val res = buildString { - val ten = 10.0 - val approxOrder = if (value == 0.0) 0 else ceil(log10(abs(value))).toInt() - val order = if ( - ((value % ten) == 0.0) || - (value == 1.0) || - ((1 / value) % ten == 0.0) - ) approxOrder else approxOrder - 1 - val lead = value / ten.pow(order) - if (value >= 0.0) append(' ') - append(round(lead * ten.pow(digits)) / ten.pow(digits)) - when { - order == 0 -> Unit - order > 0 -> { - append("e+") - append(order) - } - - else -> { - append('e') - append(order) - } - } - } - val fLength = digits + 6 - append(res) - repeat(fLength - res.length) { append(' ') } -} - -@OptIn(PerformancePitfall::class) -public fun DoubleTensor.toPrettyString(): String = buildString { - var offset = 0 - val shape = this@toPrettyString.shape - val linearStructure = this@toPrettyString.indices - val vectorSize = shape.last() - append("DoubleTensor(\n") - var charOffset = 3 - for (vector in vectorSequence()) { - repeat(charOffset) { append(' ') } - val index = linearStructure.index(offset) - for (ind in index.reversed()) { - if (ind != 0) { - break - } - append('[') - charOffset += 1 - } - - val values = vector.elements().map { format(it.second) } - - values.joinTo(this, separator = ", ") - - append(']') - charOffset -= 1 - - index.reversed().zip(shape.asList().reversed()).drop(1).forEach { (ind, maxInd) -> - if (ind != maxInd - 1) { - return@forEach - } - append(']') - charOffset -= 1 - } - - offset += vectorSize - if (this@toPrettyString.indices.linearSize == offset) { - break - } - - append(",\n") - } - append("\n)") -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt deleted file mode 100644 index e2b7c23e6..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(PerformancePitfall::class) - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.ShapeND -import kotlin.jvm.JvmName - -@JvmName("varArgOne") -public fun DoubleTensorAlgebra.one(vararg shape: Int): DoubleTensor = ones(ShapeND(shape)) - -public fun DoubleTensorAlgebra.one(shape: ShapeND): DoubleTensor = ones(shape) - -@JvmName("varArgZero") -public fun DoubleTensorAlgebra.zero(vararg shape: Int): DoubleTensor = zeros(ShapeND(shape)) - -public fun DoubleTensorAlgebra.zero(shape: ShapeND): DoubleTensor = zeros(shape) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt deleted file mode 100644 index e5dc55f68..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.covariance -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.* -import kotlin.math.min -import kotlin.math.sign - - -/** - * Returns a tensor of random numbers drawn from normal distributions with `0.0` mean and `1.0` standard deviation. - * - * @param shape the desired shape for the output tensor. - * @param seed the random seed of the pseudo-random number generator. - * @return tensor of a given shape filled with numbers from the normal distribution - * with `0.0` mean and `1.0` standard deviation. - */ -public fun DoubleTensorAlgebra.randomNormal(shape: ShapeND, seed: Long = 0): DoubleTensor = - fromBuffer(shape, DoubleBuffer.randomNormals(shape.linearSize, seed)) - -/** - * Returns a tensor with the same shape as `input` of random numbers drawn from normal distributions - * with `0.0` mean and `1.0` standard deviation. - * - * @receiver the `input`. - * @param seed the random seed of the pseudo-random number generator. - * @return a tensor with the same shape as `input` filled with numbers from the normal distribution - * with `0.0` mean and `1.0` standard deviation. - */ -public fun DoubleTensorAlgebra.randomNormalLike(structure: WithShape, seed: Long = 0): DoubleTensor = - DoubleTensor(structure.shape, DoubleBuffer.randomNormals(structure.shape.linearSize, seed)) - -/** - * Concatenates a sequence of tensors with equal shapes along the first dimension. - * - * @param tensors the [List] of tensors with same shapes to concatenate - * @return tensor with concatenation result - */ -public fun stack(tensors: List>): DoubleTensor { - check(tensors.isNotEmpty()) { "List must have at least 1 element" } - val shape = tensors[0].shape - check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } - val resShape = ShapeND(tensors.size) + shape -// val resBuffer: List = tensors.flatMap { -// it.asDoubleTensor().source.array.drop(it.asDoubleTensor().bufferStart) -// .take(it.asDoubleTensor().linearSize) -// } - val resBuffer = tensors.map { it.asDoubleTensor().source }.concat() - return DoubleTensor(resShape, resBuffer) -} - -/** - * Computes the LU factorization of a matrix or batches of matrices `input`. - * Returns a tuple containing the LU factorization and pivots of `input`. - * - * @param epsilon permissible error when comparing the determinant of a matrix with zero default is 1e-9 - * @return pair of `factorization` and `pivots`. - * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. - * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. - */ -public fun DoubleTensorAlgebra.luFactor( - structureND: StructureND, - epsilon: Double = 1e-9, -): Pair = - computeLU(structureND, epsilon) - ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") - - -/** - * Unpacks the data and pivots from a LU factorization of a tensor. - * Given a tensor [luTensor], return tensors `Triple(P, L, U)` satisfying `P dot luTensor = L dot U`, - * with `P` being a permutation matrix or batch of matrices, - * `L` being a lower triangular matrix or batch of matrices, - * `U` being an upper triangular matrix or batch of matrices. - * - * @param luTensor the packed LU factorization data - * @param pivotsTensor the packed LU factorization pivots - * @return triple of `P`, `L` and `U` tensors - */ -public fun DoubleTensorAlgebra.luPivot( - luTensor: StructureND, - pivotsTensor: Tensor, -): Triple { - checkSquareMatrix(luTensor.shape) - check( - luTensor.shape.first(luTensor.shape.size - 2) contentEquals pivotsTensor.shape.first(pivotsTensor.shape.size - 1) || - luTensor.shape.last() == pivotsTensor.shape.last() - 1 - ) { "Inappropriate shapes of input tensors" } - - val n = luTensor.shape.last() - val pTensor = zeroesLike(luTensor) - pTensor - .matrixSequence() - .zip(pivotsTensor.asIntTensor().vectorSequence()) - .forEach { (p, pivot) -> pivInit(p.asDoubleTensor2D(), pivot.as1D(), n) } - - val lTensor = zeroesLike(luTensor) - val uTensor = zeroesLike(luTensor) - - lTensor.matrixSequence() - .zip(uTensor.matrixSequence()) - .zip(luTensor.asDoubleTensor().matrixSequence()) - .forEach { (pairLU, lu) -> - val (l, u) = pairLU - luPivotHelper(l.asDoubleTensor2D(), u.asDoubleTensor2D(), lu.asDoubleTensor2D(), n) - } - - return Triple(pTensor, lTensor, uTensor) -} - - -/** - * LUP decomposition. - * - * Computes the LUP decomposition of a matrix or a batch of matrices. - * Given a tensor `input`, return tensors `Triple(P, L, U)` satisfying `P dot input == L dot U`, - * with `P` being a permutation matrix or batch of matrices, - * `L` being a lower triangular matrix or batch of matrices, - * `U` being an upper triangular matrix or batch of matrices. - * - * @param epsilon permissible error when comparing the determinant of a matrix with zero. - * @return triple of `P`, `L` and `U` tensors. - */ -public fun DoubleTensorAlgebra.lu( - structureND: StructureND, - epsilon: Double = 1e-9, -): Triple { - val (lu, pivots) = luFactor(structureND, epsilon) - return luPivot(lu, pivots) -} - - -/** - * QR decomposition. - * - * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `Q to R` of tensors. - * Given a tensor `input`, return tensors `Q to R` satisfying `input == Q dot R`, - * with `Q` being an orthogonal matrix or batch of orthogonal matrices - * and `R` being an upper triangular matrix or batch of upper triangular matrices. - * - * @receiver the `input`. - * @param epsilon the permissible error when comparing tensors for equality. The default is 1e-6 - * Used when checking the positive definiteness of the input matrix or matrices. - * @return a pair of `Q` and `R` tensors. - */ -public fun DoubleTensorAlgebra.cholesky(structureND: StructureND, epsilon: Double = 1e-6): DoubleTensor { - checkSquareMatrix(structureND.shape) - checkPositiveDefinite(structureND.asDoubleTensor(), epsilon) - - val n = structureND.shape.last() - val lTensor = zeroesLike(structureND) - - for ((a, l) in structureND.asDoubleTensor().matrixSequence().zip(lTensor.matrixSequence())) - for (i in 0 until n) choleskyHelper(a.asDoubleTensor2D(), l.asDoubleTensor2D(), n) - - return lTensor -} - - -/** - * Singular Value Decomposition. - * - * Computes the singular value decomposition of either a matrix or batch of matrices `input`. - * The singular value decomposition is represented as a triple `Triple(U, S, V)`, - * such that `input == U dot diagonalEmbedding(S) dot V.transpose()`. - * If `input` is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as `input. - * - * @receiver the `input`. - * @param epsilon permissible error when calculating the dot product of vectors - * i.e., the precision with which the cosine approaches 1 in an iterative algorithm. - * @return a triple `Triple(U, S, V)`. - */ -public fun DoubleTensorAlgebra.svd( - structureND: StructureND, - epsilon: Double, -): Triple, StructureND, StructureND> { - val size = structureND.dimension - val commonShape = structureND.shape.slice(0 until size - 2) - val (n, m) = structureND.shape.slice(size - 2 until size) - val uTensor = zeros(commonShape + ShapeND(min(n, m), n)) - val sTensor = zeros(commonShape + ShapeND(min(n, m))) - val vTensor = zeros(commonShape + ShapeND(min(n, m), m)) - - val matrices = structureND.asDoubleTensor().matrices - val uTensors = uTensor.matrices - val sTensorVectors = sTensor.vectors - val vTensors = vTensor.matrices - - for (index in matrices.indices) { - val matrix = matrices[index] - val usv = Triple( - uTensors[index], - sTensorVectors[index], - vTensors[index] - ) - val matrixSize = matrix.shape.linearSize - val curMatrix = DoubleTensor( - matrix.shape, - matrix.source.view(0, matrixSize) - ) - svdHelper(curMatrix, usv, m, n, epsilon) - } - - return Triple(uTensor.transposed(), sTensor, vTensor.transposed()) -} - -/** - * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, - * represented by a pair `eigenvalues to eigenvectors`. - * - * @param epsilon the permissible error when comparing tensors for equality - * and when the cosine approaches 1 in the SVD algorithm. - * @return a pair `eigenvalues to eigenvectors`. - */ -public fun DoubleTensorAlgebra.symEigSvd( - structureND: StructureND, - epsilon: Double, -): Pair> { - //TODO optimize conversion - checkSymmetric(structureND.asDoubleTensor(), epsilon) - - fun MutableStructure2D.cleanSym(n: Int) { - for (i in 0 until n) { - for (j in 0 until n) { - if (i == j) { - this[i, j] = sign(this[i, j]) - } else { - this[i, j] = 0.0 - } - } - } - } - - val (u, s, v) = svd(structureND, epsilon) - val shp = s.shape + intArrayOf(1) - val utv = u.transposed() matmul v - val n = s.shape.last() - for (matrix in utv.matrixSequence()) { - matrix.asDoubleTensor2D().cleanSym(n) - } - - val eig = (utv dot s.asDoubleTensor().view(shp)).view(s.shape) - return eig to v -} - -public fun DoubleTensorAlgebra.symEigJacobi( - structureND: StructureND, - maxIteration: Int, - epsilon: Double, -): Pair { - //TODO optimize conversion - checkSymmetric(structureND.asDoubleTensor(), epsilon) - - val size = structureND.dimension - val eigenvectors = zeros(structureND.shape) - val eigenvalues = zeros(structureND.shape.slice(0 until size - 1)) - - var eigenvalueStart = 0 - var eigenvectorStart = 0 - for (matrix in structureND.asDoubleTensor().matrixSequence()) { - val matrix2D = matrix.asDoubleTensor2D() - val (d, v) = matrix2D.jacobiHelper(maxIteration, epsilon) - - for (i in 0 until matrix2D.rowNum) { - for (j in 0 until matrix2D.colNum) { - eigenvectors.source[eigenvectorStart + i * matrix2D.rowNum + j] = v[i, j] - } - } - - for (i in 0 until matrix2D.rowNum) { - eigenvalues.source[eigenvalueStart + i] = d[i] - } - - eigenvalueStart += structureND.shape.last() - eigenvectorStart += structureND.shape.last() * structureND.shape.last() - } - - return eigenvalues to eigenvectors -} - -/** - * Computes the determinant of a square matrix input, or of each square matrix in a batched input - * using LU factorization algorithm. - * - * @param epsilon the error in the LU algorithm—permissible error when comparing the determinant of a matrix - * with zero. - * @return the determinant. - */ -public fun DoubleTensorAlgebra.detLU(structureND: StructureND, epsilon: Double = 1e-9): DoubleTensor { - checkSquareMatrix(structureND.shape) - //TODO check for unnecessary copies - val luTensor = structureND.copyToTensor() - val pivotsTensor = structureND.setUpPivots() - - val n = structureND.shape.size - - val detTensorShape = ShapeND(IntArray(n - 1) { i -> structureND.shape[i] }.apply { - set(n - 2, 1) - }) - - val resBuffer = DoubleBuffer(detTensorShape.linearSize) { 0.0 } - - val detTensor = DoubleTensor( - detTensorShape, - resBuffer - ) - - luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).forEachIndexed { index, (lu, pivots) -> - resBuffer[index] = if (luHelper(lu.asDoubleTensor2D(), pivots.as1D(), epsilon)) - 0.0 else luMatrixDet(lu.asDoubleTensor2D(), pivots.as1D()) - } - - return detTensor -} - -/** - * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input - * using LU factorization algorithm. - * Given a square matrix `a`, return the matrix `aInv` satisfying - * `a dot aInv == aInv dot a == eye(a.shape[0])`. - * - * @param epsilon error in the LU algorithm—permissible error when comparing the determinant of a matrix with zero - * @return the multiplicative inverse of a matrix. - */ -public fun DoubleTensorAlgebra.invLU(structureND: StructureND, epsilon: Double = 1e-9): DoubleTensor { - val (luTensor, pivotsTensor) = luFactor(structureND, epsilon) - val invTensor = zeroesLike(luTensor) - - //TODO replace sequence with a cycle - val seq = luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) - for ((luP, invMatrix) in seq) { - val (lu, pivots) = luP - luMatrixInv(lu.asDoubleTensor2D(), pivots.as1D(), invMatrix.asDoubleTensor2D()) - } - - return invTensor -} - -/** - * Returns the covariance matrix `M` of given vectors. - * - * `M[i, j]` contains covariance of `i`-th and `j`-th given vectors - * - * @param vectors the [List] of 1-dimensional tensors with same shape - * @return `M`. - */ -public fun DoubleTensorAlgebra.covariance(vectors: List>): DoubleTensor { - check(vectors.isNotEmpty()) { "List must have at least 1 element" } - val n = vectors.size - val m = vectors[0].size - check(vectors.all { it.size == m }) { "Vectors must have same shapes" } - val resTensor = DoubleTensor( - ShapeND(n, n), - DoubleBuffer(n * n) { 0.0 } - ) - for (i in 0 until n) { - for (j in 0 until n) { - resTensor[intArrayOf(i, j)] = bufferAlgebra.covariance(vectors[i], vectors[j]) - } - } - return resTensor -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt deleted file mode 100644 index 3b0d15400..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.nd.* -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.tensors.api.Tensor - - -/** - * Create a mutable copy of given [StructureND]. - */ -public fun StructureND.copyToTensor(): DoubleTensor = if (this is DoubleTensor) { - DoubleTensor(shape, source.copy()) -} else if (this is DoubleBufferND && indices is RowStrides) { - DoubleTensor(shape, buffer.copy()) -} else { - DoubleTensor( - shape, - RowStrides(this.shape).map(this::getDouble).toDoubleArray().asBuffer(), - ) -} - -public fun StructureND.toDoubleTensor(): DoubleTensor { - return if (this is IntTensor) { - DoubleTensor( - shape, - DoubleBuffer(linearSize) { source[it].toDouble() } - ) - } else { - val tensor = DoubleTensorAlgebra.zeroesLike(this) - indices.forEach { - tensor[it] = getInt(it).toDouble() - } - return tensor - } -} - -/** - * Transforms [StructureND] of [Double] to [DoubleTensor]. Zero copy if possible, but is not guaranteed - */ -public fun StructureND.asDoubleTensor(): DoubleTensor = if (this is DoubleTensor) { - this -} else if (this is DoubleBufferND && indices is RowStrides) { - DoubleTensor(shape, buffer) -} else { - copyToTensor() -} - -/** - * Casts [Tensor] of [Int] to [IntTensor] - */ -public fun StructureND.asIntTensor(): IntTensor = when (this) { - is IntTensor -> this - else -> IntTensor( - shape, - RowStrides(shape).map(this::getInt).toIntArray().asBuffer() - ) -} \ No newline at end of file diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt deleted file mode 100644 index 73aed8a7b..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.contentEquals -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.internal.broadcastOuterTensors -import space.kscience.kmath.tensors.core.internal.broadcastShapes -import space.kscience.kmath.tensors.core.internal.broadcastTensors -import space.kscience.kmath.tensors.core.internal.broadcastTo -import kotlin.test.Test -import kotlin.test.assertTrue - -internal class TestBroadcasting { - - @Test - fun testBroadcastShapes() = DoubleTensorAlgebra { - assertTrue( - broadcastShapes( - listOf(ShapeND(2, 3), ShapeND(1, 3), ShapeND(1, 1, 1)) - ) contentEquals ShapeND(1, 2, 3) - ) - - assertTrue( - broadcastShapes( - listOf(ShapeND(6, 7), ShapeND(5, 6, 1), ShapeND(7), ShapeND(5, 1, 7)) - ) contentEquals ShapeND(5, 6, 7) - ) - } - - @Test - fun testBroadcastTo() = DoubleTensorAlgebra { - val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(ShapeND(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - - val res = broadcastTo(tensor2, tensor1.shape) - assertTrue(res.shape contentEquals ShapeND(2, 3)) - assertTrue(res.source contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) - } - - @Test - fun testBroadcastTensors() = DoubleTensorAlgebra { - val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(ShapeND(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = fromArray(ShapeND(1, 1, 1), doubleArrayOf(500.0)) - - val res = broadcastTensors(tensor1, tensor2, tensor3) - - assertTrue(res[0].shape contentEquals ShapeND(1, 2, 3)) - assertTrue(res[1].shape contentEquals ShapeND(1, 2, 3)) - assertTrue(res[2].shape contentEquals ShapeND(1, 2, 3)) - - assertTrue(res[0].source contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res[1].source contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) - assertTrue(res[2].source contentEquals doubleArrayOf(500.0, 500.0, 500.0, 500.0, 500.0, 500.0)) - } - - @Test - fun testBroadcastOuterTensors() = DoubleTensorAlgebra { - val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(ShapeND(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = fromArray(ShapeND(1, 1, 1), doubleArrayOf(500.0)) - - val res = broadcastOuterTensors(tensor1, tensor2, tensor3) - - assertTrue(res[0].shape contentEquals ShapeND(1, 2, 3)) - assertTrue(res[1].shape contentEquals ShapeND(1, 1, 3)) - assertTrue(res[2].shape contentEquals ShapeND(1, 1, 1)) - - assertTrue(res[0].source contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res[1].source contentEquals doubleArrayOf(10.0, 20.0, 30.0)) - assertTrue(res[2].source contentEquals doubleArrayOf(500.0)) - } - - @Test - fun testBroadcastOuterTensorsShapes() = DoubleTensorAlgebra { - val tensor1 = fromArray(ShapeND(2, 1, 3, 2, 3), DoubleArray(2 * 1 * 3 * 2 * 3) { 0.0 }) - val tensor2 = fromArray(ShapeND(4, 2, 5, 1, 3, 3), DoubleArray(4 * 2 * 5 * 1 * 3 * 3) { 0.0 }) - val tensor3 = fromArray(ShapeND(1, 1), doubleArrayOf(500.0)) - - val res = broadcastOuterTensors(tensor1, tensor2, tensor3) - - assertTrue(res[0].shape contentEquals ShapeND(4, 2, 5, 3, 2, 3)) - assertTrue(res[1].shape contentEquals ShapeND(4, 2, 5, 3, 3, 3)) - assertTrue(res[2].shape contentEquals ShapeND(4, 2, 5, 3, 1, 1)) - } - - @Test - fun testMinusTensor() = BroadcastDoubleTensorAlgebra.invoke { - val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(ShapeND(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = fromArray(ShapeND(1, 1, 1), doubleArrayOf(500.0)) - - val tensor21 = tensor2 - tensor1 - val tensor31 = tensor3 - tensor1 - val tensor32 = tensor3 - tensor2 - - assertTrue(tensor21.shape contentEquals ShapeND(2, 3)) - assertTrue(tensor21.source contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0)) - - assertTrue(tensor31.shape contentEquals ShapeND(1, 2, 3)) - assertTrue( - tensor31.source - contentEquals doubleArrayOf(499.0, 498.0, 497.0, 496.0, 495.0, 494.0) - ) - - assertTrue(tensor32.shape contentEquals ShapeND(1, 1, 3)) - assertTrue(tensor32.source contentEquals doubleArrayOf(490.0, 480.0, 470.0)) - } - -} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt deleted file mode 100644 index e4c2c40ea..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.asBuffer -import kotlin.math.* -import kotlin.test.Test -import kotlin.test.assertTrue - -internal class TestDoubleAnalyticTensorAlgebra { - - val shape = ShapeND(2, 1, 3, 2) - val buffer = doubleArrayOf( - 27.1, 20.0, 19.84, - 23.123, 3.0, 2.0, - - 3.23, 133.7, 25.3, - 100.3, 11.0, 12.012 - ) - val tensor = DoubleTensor(shape, buffer.asBuffer()) - - fun DoubleArray.fmap(transform: (Double) -> Double): DoubleArray { - return this.map(transform).toDoubleArray() - } - - fun expectedTensor(transform: (Double) -> Double): DoubleTensor { - return DoubleTensor(shape, buffer.fmap(transform).asBuffer()) - } - - @Test - fun testExp() = DoubleTensorAlgebra { - assertTrue { exp(tensor) eq expectedTensor(::exp) } - } - - @Test - fun testLog() = DoubleTensorAlgebra { - assertTrue { ln(tensor) eq expectedTensor(::ln) } - } - - @Test - fun testSqrt() = DoubleTensorAlgebra { - assertTrue { sqrt(tensor) eq expectedTensor(::sqrt) } - } - - @Test - fun testCos() = DoubleTensorAlgebra { - assertTrue { cos(tensor) eq expectedTensor(::cos) } - } - - - @Test - fun testCosh() = DoubleTensorAlgebra { - assertTrue { cosh(tensor) eq expectedTensor(::cosh) } - } - - @Test - fun testAcosh() = DoubleTensorAlgebra { - assertTrue { acosh(tensor) eq expectedTensor(::acosh) } - } - - @Test - fun testSin() = DoubleTensorAlgebra { - assertTrue { sin(tensor) eq expectedTensor(::sin) } - } - - @Test - fun testSinh() = DoubleTensorAlgebra { - assertTrue { sinh(tensor) eq expectedTensor(::sinh) } - } - - @Test - fun testAsinh() = DoubleTensorAlgebra { - assertTrue { asinh(tensor) eq expectedTensor(::asinh) } - } - - @Test - fun testTan() = DoubleTensorAlgebra { - assertTrue { tan(tensor) eq expectedTensor(::tan) } - } - - @Test - fun testAtan() = DoubleTensorAlgebra { - assertTrue { atan(tensor) eq expectedTensor(::atan) } - } - - @Test - fun testTanh() = DoubleTensorAlgebra { - assertTrue { tanh(tensor) eq expectedTensor(::tanh) } - } - - @Test - fun testCeil() = DoubleTensorAlgebra { - assertTrue { ceil(tensor) eq expectedTensor(::ceil) } - } - - @Test - fun testFloor() = DoubleTensorAlgebra { - assertTrue { floor(tensor) eq expectedTensor(::floor) } - } - - val shape2 = ShapeND(2, 2) - val buffer2 = doubleArrayOf( - 1.0, 2.0, - -3.0, 4.0 - ) - val tensor2 = DoubleTensor(shape2, buffer2.asBuffer()) - - @Test - fun testMin() = DoubleTensorAlgebra { - assertTrue { tensor2.min() == -3.0 } - assertTrue { - tensor2.min(0, true) eq fromArray( - ShapeND(1, 2), - doubleArrayOf(-3.0, 2.0) - ) - } - assertTrue { - tensor2.min(1, false) eq fromArray( - ShapeND(2), - doubleArrayOf(1.0, -3.0) - ) - } - } - - @Test - fun testMax() = DoubleTensorAlgebra { - assertTrue { tensor2.max() == 4.0 } - assertTrue { - tensor2.max(0, true) eq fromArray( - ShapeND(1, 2), - doubleArrayOf(1.0, 4.0) - ) - } - assertTrue { - tensor2.max(1, false) eq fromArray( - ShapeND(2), - doubleArrayOf(2.0, 4.0) - ) - } - } - - @Test - fun testSum() = DoubleTensorAlgebra { - assertTrue { tensor2.sum() == 4.0 } - assertTrue { - tensor2.sum(0, true) eq fromArray( - ShapeND(1, 2), - doubleArrayOf(-2.0, 6.0) - ) - } - assertTrue { - tensor2.sum(1, false) eq fromArray( - ShapeND(2), - doubleArrayOf(3.0, 1.0) - ) - } - } - - @Test - fun testMean() = DoubleTensorAlgebra { - assertTrue { mean(tensor2) == 1.0 } - assertTrue { - mean(tensor2, 0, true) eq fromArray( - ShapeND(1, 2), - doubleArrayOf(-1.0, 3.0) - ) - } - assertTrue { - mean(tensor2, 1, false) eq fromArray( - ShapeND(2), - doubleArrayOf(1.5, 0.5) - ) - } - } - -} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt deleted file mode 100644 index cbd7b9887..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.contentEquals -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.internal.svd1d -import kotlin.math.abs -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -internal class TestDoubleLinearOpsTensorAlgebra { - - @Test - fun testDetLU() = DoubleTensorAlgebra { - val tensor = fromArray( - ShapeND(2, 2, 2), - doubleArrayOf( - 1.0, 3.0, - 1.0, 2.0, - 1.5, 1.0, - 10.0, 2.0 - ) - ) - - val expectedTensor = fromArray( - ShapeND(2, 1), - doubleArrayOf( - -1.0, - -7.0 - ) - ) - val detTensor = detLU(tensor) - - assertTrue(detTensor.eq(expectedTensor)) - - } - - @Test - fun testDet() = DoubleTensorAlgebra { - val expectedValue = 0.019827417 - val m = fromArray( - ShapeND(3, 3), doubleArrayOf( - 2.1843, 1.4391, -0.4845, - 1.4391, 1.7772, 0.4055, - -0.4845, 0.4055, 0.7519 - ) - ) - - assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } - } - - @Test - fun testDetSingle() = DoubleTensorAlgebra { - val expectedValue = 48.151623 - val m = fromArray( - ShapeND(1, 1), doubleArrayOf( - expectedValue - ) - ) - - assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } - } - - @Test - fun testInvLU() = DoubleTensorAlgebra { - val tensor = fromArray( - ShapeND(2, 2, 2), - doubleArrayOf( - 1.0, 0.0, - 0.0, 2.0, - 1.0, 1.0, - 1.0, 0.0 - ) - ) - - val expectedTensor = fromArray( - ShapeND(2, 2, 2), doubleArrayOf( - 1.0, 0.0, - 0.0, 0.5, - 0.0, 1.0, - 1.0, -1.0 - ) - ) - - val invTensor = invLU(tensor) - assertTrue(invTensor.eq(expectedTensor)) - } - - @Test - fun testScalarProduct() = DoubleTensorAlgebra { - val a = fromArray(ShapeND(3), doubleArrayOf(1.8, 2.5, 6.8)) - val b = fromArray(ShapeND(3), doubleArrayOf(5.5, 2.6, 6.4)) - assertEquals(a.dot(b).value(), 59.92) - } - - @Test - fun testQR() = DoubleTensorAlgebra { - val shape = ShapeND(2, 2, 2) - val buffer = doubleArrayOf( - 1.0, 3.0, - 1.0, 2.0, - 1.5, 1.0, - 10.0, 2.0 - ) - - val tensor = fromArray(shape, buffer) - - val (q, r) = qr(tensor) - - assertTrue { q.shape contentEquals shape } - assertTrue { r.shape contentEquals shape } - - assertTrue((q matmul r).eq(tensor)) - - } - - @Test - fun testLU() = DoubleTensorAlgebra { - val shape = ShapeND(2, 2, 2) - val buffer = doubleArrayOf( - 1.0, 3.0, - 1.0, 2.0, - 1.5, 1.0, - 10.0, 2.0 - ) - val tensor = fromArray(shape, buffer) - - val (p, l, u) = lu(tensor) - - assertTrue { p.shape contentEquals shape } - assertTrue { l.shape contentEquals shape } - assertTrue { u.shape contentEquals shape } - - assertTrue((p matmul tensor).eq(l matmul u)) - } - - @Test - fun testCholesky() = DoubleTensorAlgebra { - val tensor = randomNormal(ShapeND(2, 5, 5), 0) - val sigma = (tensor matmul tensor.transposed()) + diagonalEmbedding( - fromArray(ShapeND(2, 5), DoubleArray(10) { 0.1 }) - ) - val low = cholesky(sigma) - val sigmChol = low matmul low.transposed() - assertTrue(sigma.eq(sigmChol)) - } - - @Test - fun testSVD1D() = DoubleTensorAlgebra { - val tensor2 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - - val res = svd1d(tensor2) - - assertTrue(res.shape contentEquals ShapeND(2)) - assertTrue { abs(abs(res.source[0]) - 0.386) < 0.01 } - assertTrue { abs(abs(res.source[1]) - 0.922) < 0.01 } - } - - @Test - fun testSVD() = DoubleTensorAlgebra { - testSVDFor(fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))) - testSVDFor(fromArray(ShapeND(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0))) - } - - @Test - fun testBatchedSVD() = DoubleTensorAlgebra { - val tensor = randomNormal(ShapeND(2, 5, 3), 0) - val (tensorU, tensorS, tensorV) = svd(tensor) - val tensorSVD = tensorU matmul (diagonalEmbedding(tensorS) matmul tensorV.transposed()) - assertTrue(tensor.eq(tensorSVD)) - } - - @Test - fun testBatchedSymEig() = DoubleTensorAlgebra { - val tensor = randomNormal(shape = ShapeND(2, 3, 3), 0) - val tensorSigma = tensor + tensor.transposed() - val (tensorS, tensorV) = symEig(tensorSigma) - val tensorSigmaCalc = tensorV matmul (diagonalEmbedding(tensorS) matmul tensorV.transposed()) - assertTrue(tensorSigma.eq(tensorSigmaCalc)) - } - - -} - - -private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10) { - val svd = svd(tensor) - - val tensorSVD = svd.first - .dot( - diagonalEmbedding(svd.second) - .dot(svd.third.transposed()) - ) - - assertTrue(tensor.eq(tensorSVD, epsilon)) -} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt deleted file mode 100644 index 811fc1117..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.toDoubleArray -import space.kscience.kmath.tensors.core.internal.matrixSequence -import space.kscience.kmath.testutils.assertBufferEquals -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -@OptIn(PerformancePitfall::class) -internal class TestDoubleTensor { - - @Test - fun testValue() = DoubleTensorAlgebra { - val value = 12.5 - val tensor = fromArray(ShapeND(1), doubleArrayOf(value)) - assertEquals(tensor.value(), value) - } - - @OptIn(PerformancePitfall::class) - @Test - fun testStrides() = DoubleTensorAlgebra { - val tensor = fromArray(ShapeND(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) - assertEquals(tensor[intArrayOf(0, 1)], 5.8) - assertTrue( - tensor.elements().map { it.second }.toList() - .toDoubleArray() contentEquals tensor.source.toDoubleArray() - ) - } - - @Test - fun testGet() = DoubleTensorAlgebra { - val tensor = fromArray(ShapeND(1, 2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) - val matrix = tensor.getTensor(0).asDoubleTensor2D() - assertEquals(matrix[0, 1], 5.8) - - val vector = tensor.getTensor(0, 1).as1D() - assertEquals(vector[0], 58.4) - - matrix[0, 1] = 77.89 - assertEquals(tensor[intArrayOf(0, 0, 1)], 77.89) - - vector[0] = 109.56 - assertEquals(tensor[intArrayOf(0, 1, 0)], 109.56) - - tensor.matrixSequence().forEach { - val a = it.asDoubleTensor() - val secondRow = a.getTensor(1).asDoubleBuffer() - val secondColumn = a.transposed(0, 1).getTensor(1).asDoubleBuffer() - assertEquals(secondColumn[0], 77.89) - assertEquals(secondRow[1], secondColumn[1]) - } - } - - @Test - fun testNoBufferProtocol() { - - // create buffer - val doubleArray = DoubleBuffer(1.0, 2.0, 3.0) - - // create ND buffers, no data is copied - val ndArray: MutableBufferND = DoubleBufferND(ColumnStrides(ShapeND(3)), doubleArray) - - // map to tensors - val tensorArray = ndArray.asDoubleTensor() // Data is copied because of strides change. - - //protective copy - val tensorArrayPublic = ndArray.copyToTensor() // public API, data copied twice - val sharedTensorArray = tensorArrayPublic.asDoubleTensor() // no data copied by matching type - - assertTrue(tensorArray.source contentEquals sharedTensorArray.source) - - tensorArray[intArrayOf(0)] = 55.9 - assertEquals(tensorArrayPublic[intArrayOf(0)], 1.0) - - tensorArrayPublic[intArrayOf(0)] = 57.9 - assertEquals(sharedTensorArray[intArrayOf(0)], 57.9) - assertEquals(tensorArray[intArrayOf(0)], 55.9) - - tensorArray[intArrayOf(0)] = 55.9 - assertEquals(ndArray[intArrayOf(0)], 1.0) - } - - @Test - fun test2D() = with(DoubleTensorAlgebra) { - val tensor: DoubleTensor = structureND(ShapeND(3, 3)) { (i, j) -> (i - j).toDouble() } - //println(tensor.toPrettyString()) - val tensor2d = tensor.asDoubleTensor2D() - assertBufferEquals(DoubleBuffer(1.0, 0.0, -1.0), tensor2d.rows[1]) - assertBufferEquals(DoubleBuffer(-2.0, -1.0, 0.0), tensor2d.columns[2]) - } - - @Test - fun testMatrixIteration() = with(DoubleTensorAlgebra) { - val tensor = structureND(ShapeND(3, 3, 3, 3)) { index -> index.sum().toDouble() } - tensor.forEachMatrix { index, matrix -> - println(index.joinToString { it.toString() }) - println(matrix) - } - } -} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt deleted file mode 100644 index cae01bed8..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - - -import space.kscience.kmath.nd.ShapeND -import space.kscience.kmath.nd.contentEquals -import space.kscience.kmath.nd.get -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.testutils.assertBufferEquals -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -internal class TestDoubleTensorAlgebra { - - @Test - fun testDoublePlus() = DoubleTensorAlgebra { - val tensor = fromArray(ShapeND(2), doubleArrayOf(1.0, 2.0)) - val res = 10.0 + tensor - assertTrue(res.source contentEquals doubleArrayOf(11.0, 12.0)) - } - - @Test - fun testDoubleDiv() = DoubleTensorAlgebra { - val tensor = fromArray(ShapeND(2), doubleArrayOf(2.0, 4.0)) - val res = 2.0 / tensor - assertTrue(res.source contentEquals doubleArrayOf(1.0, 0.5)) - } - - @Test - fun testDivDouble() = DoubleTensorAlgebra { - val tensor = fromArray(ShapeND(2), doubleArrayOf(10.0, 5.0)) - val res = tensor / 2.5 - assertTrue(res.source contentEquals doubleArrayOf(4.0, 2.0)) - } - - @Test - fun testTranspose1x1() = DoubleTensorAlgebra { - val tensor = fromArray(ShapeND(1), doubleArrayOf(0.0)) - val res = tensor.transposed(0, 0) - - assertTrue(res.asDoubleTensor().source contentEquals doubleArrayOf(0.0)) - assertTrue(res.shape contentEquals ShapeND(1)) - } - - @Test - fun testTranspose3x2() = DoubleTensorAlgebra { - val tensor = fromArray(ShapeND(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val res = tensor.transposed(1, 0) - - assertTrue(res.asDoubleTensor().source contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.0)) - assertTrue(res.shape contentEquals ShapeND(2, 3)) - } - - @Test - fun testTranspose1x2x3() = DoubleTensorAlgebra { - val tensor = fromArray(ShapeND(1, 2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val res01 = tensor.transposed(0, 1) - val res02 = tensor.transposed(-3, 2) - val res12 = tensor.transposed() - - assertTrue(res01.shape contentEquals ShapeND(2, 1, 3)) - assertTrue(res02.shape contentEquals ShapeND(3, 2, 1)) - assertTrue(res12.shape contentEquals ShapeND(1, 3, 2)) - - assertTrue(res01.asDoubleTensor().source contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res02.asDoubleTensor().source contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) - assertTrue(res12.asDoubleTensor().source contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) - } - - @Test - fun testLinearStructure() = DoubleTensorAlgebra { - val shape = ShapeND(3) - val tensorA = full(value = -4.5, shape = shape) - val tensorB = full(value = 10.9, shape = shape) - val tensorC = full(value = 789.3, shape = shape) - val tensorD = full(value = -72.9, shape = shape) - val tensorE = full(value = 553.1, shape = shape) - val result = 15.8 * tensorA - 1.5 * tensorB * (-tensorD) + 0.02 * tensorC / tensorE - 39.4 - - val expected = fromArray( - shape, - (1..3).map { - 15.8 * (-4.5) - 1.5 * 10.9 * 72.9 + 0.02 * 789.3 / 553.1 - 39.4 - }.toDoubleArray() - ) - - val assignResult = zeros(shape) - tensorA *= 15.8 - tensorB *= 1.5 - tensorB *= -tensorD - tensorC *= 0.02 - tensorC /= tensorE - assignResult += tensorA - assignResult -= tensorB - assignResult += tensorC - assignResult += -39.4 - - assertBufferEquals(expected.source, result.source) - assertBufferEquals(expected.source, assignResult.source) - } - - @Test - fun testDot() = DoubleTensorAlgebra { - val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor11 = fromArray(ShapeND(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(ShapeND(3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = fromArray(ShapeND(1, 1, 3), doubleArrayOf(-1.0, -2.0, -3.0)) - val tensor4 = fromArray(ShapeND(2, 3, 3), (1..18).map { it.toDouble() }.toDoubleArray()) - val tensor5 = fromArray(ShapeND(2, 3, 3), (1..18).map { 1 + it.toDouble() }.toDoubleArray()) - - val res12 = tensor1.dot(tensor2) - assertTrue(res12.source contentEquals doubleArrayOf(140.0, 320.0)) - assertTrue(res12.shape contentEquals ShapeND(2)) - - val res32 = tensor3.matmul(tensor2) - assertTrue(res32.source contentEquals doubleArrayOf(-140.0)) - assertTrue(res32.shape contentEquals ShapeND(1, 1)) - - val res22 = tensor2.dot(tensor2) - assertTrue(res22.source contentEquals doubleArrayOf(1400.0)) - assertTrue(res22.shape contentEquals ShapeND(1)) - - val res11 = tensor1.dot(tensor11) - assertTrue(res11.source contentEquals doubleArrayOf(22.0, 28.0, 49.0, 64.0)) - assertTrue(res11.shape contentEquals ShapeND(2, 2)) - - val res45 = tensor4.matmul(tensor5) - assertTrue( - res45.source contentEquals doubleArrayOf( - 36.0, 42.0, 48.0, 81.0, 96.0, 111.0, 126.0, 150.0, 174.0, - 468.0, 501.0, 534.0, 594.0, 636.0, 678.0, 720.0, 771.0, 822.0 - ) - ) - assertTrue(res45.shape contentEquals ShapeND(2, 3, 3)) - } - - @Test - fun testDiagonalEmbedding() = DoubleTensorAlgebra { - val tensor1 = fromArray(ShapeND(3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor2 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor3 = zeros(ShapeND(2, 3, 4, 5)) - - assertTrue( - diagonalEmbedding(tensor3, 0, 3, 4).shape contentEquals - ShapeND(2, 3, 4, 5, 5) - ) - assertTrue( - diagonalEmbedding(tensor3, 1, 3, 4).shape contentEquals - ShapeND(2, 3, 4, 6, 6) - ) - assertTrue( - diagonalEmbedding(tensor3, 2, 0, 3).shape contentEquals - ShapeND(7, 2, 3, 7, 4) - ) - - val diagonal1 = diagonalEmbedding(tensor1, 0, 1, 0) - assertTrue(diagonal1.shape contentEquals ShapeND(3, 3)) - assertTrue( - diagonal1.source contentEquals - doubleArrayOf(10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0) - ) - - val diagonal1Offset = diagonalEmbedding(tensor1, 1, 1, 0) - assertTrue(diagonal1Offset.shape contentEquals ShapeND(4, 4)) - assertTrue( - diagonal1Offset.source contentEquals - doubleArrayOf(0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 30.0, 0.0) - ) - - val diagonal2 = diagonalEmbedding(tensor2, 1, 0, 2) - assertTrue(diagonal2.shape contentEquals ShapeND(4, 2, 4)) - assertTrue( - diagonal2.source contentEquals - doubleArrayOf( - 0.0, 1.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, - 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 5.0, 0.0, - 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 6.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 - ) - ) - } - - @Test - fun testEq() = DoubleTensorAlgebra { - val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor3 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0)) - - assertTrue(tensor1 eq tensor1) - assertTrue(tensor1 eq tensor2) - assertFalse(tensor1.eq(tensor3)) - - } - - @Test - fun testMap() = DoubleTensorAlgebra { - val tensor = one(5, 5, 5) - val l = tensor.getTensor(0).map { it + 1.0 } - val r = tensor.getTensor(1).map { it - 1.0 } - val res = l + r - assertTrue { ShapeND(5, 5) contentEquals res.shape } - assertEquals(2.0, res[4, 4]) - } -} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt deleted file mode 100644 index e9fc7fb9c..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.indices -import kotlin.jvm.JvmName - - -/** - * Simplified [DoubleBuffer] to array comparison - */ -public fun OffsetDoubleBuffer.contentEquals(vararg doubles: Double): Boolean = indices.all { get(it) == doubles[it] } - -@JvmName("contentEqualsArray") -public infix fun OffsetDoubleBuffer.contentEquals(otherArray: DoubleArray): Boolean = contentEquals(*otherArray) - -@JvmName("contentEqualsBuffer") -public infix fun OffsetDoubleBuffer.contentEquals(otherBuffer: Buffer): Boolean = - indices.all { get(it) == otherBuffer[it] } \ No newline at end of file diff --git a/kmath-viktor/README.md b/kmath-viktor/README.md deleted file mode 100644 index 8a781af4c..000000000 --- a/kmath-viktor/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-viktor - -Binding for https://github.com/JetBrains-Research/viktor - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-viktor:0.4.0-dev-1`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-viktor:0.4.0-dev-1' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-viktor:0.4.0-dev-1") -} -``` diff --git a/kmath-viktor/api/kmath-viktor.api b/kmath-viktor/api/kmath-viktor.api index 39ae1f84c..59882627b 100644 --- a/kmath-viktor/api/kmath-viktor.api +++ b/kmath-viktor/api/kmath-viktor.api @@ -1,69 +1,40 @@ public final class space/kscience/kmath/viktor/ViktorBuffer : space/kscience/kmath/structures/MutableBuffer { - public static final synthetic fun box-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Lspace/kscience/kmath/viktor/ViktorBuffer; - public static fun constructor-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Lorg/jetbrains/bio/viktor/F64FlatArray; + public fun (Lorg/jetbrains/bio/viktor/F64FlatArray;)V public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public static fun copy-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Lspace/kscience/kmath/structures/MutableBuffer; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;Ljava/lang/Object;)Z - public static final fun equals-impl0 (Lorg/jetbrains/bio/viktor/F64FlatArray;Lorg/jetbrains/bio/viktor/F64FlatArray;)Z public fun get (I)Ljava/lang/Double; public synthetic fun get (I)Ljava/lang/Object; - public static fun get-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;I)Ljava/lang/Double; public final fun getFlatArray ()Lorg/jetbrains/bio/viktor/F64FlatArray; public fun getSize ()I - public static fun getSize-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)I - public fun hashCode ()I - public static fun hashCode-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)I public fun iterator ()Ljava/util/Iterator; - public static fun iterator-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Ljava/util/Iterator; public fun set (ID)V public synthetic fun set (ILjava/lang/Object;)V - public static fun set-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;ID)V - public fun toString ()Ljava/lang/String; - public static fun toString-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Ljava/lang/String; - public final synthetic fun unbox-impl ()Lorg/jetbrains/bio/viktor/F64FlatArray; } -public class space/kscience/kmath/viktor/ViktorFieldND : space/kscience/kmath/viktor/ViktorFieldOpsND, space/kscience/kmath/nd/FieldND, space/kscience/kmath/operations/NumbersAddOps { +public final class space/kscience/kmath/viktor/ViktorFieldND : space/kscience/kmath/nd/FieldND, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/ScaleOperations { public fun ([I)V - public synthetic fun getOne ()Ljava/lang/Object; - public synthetic fun getOne ()Lspace/kscience/kmath/nd/StructureND; - public fun getOne ()Lspace/kscience/kmath/viktor/ViktorStructureND; - public fun getShape-IIYLAfE ()[I - public synthetic fun getZero ()Ljava/lang/Object; - public synthetic fun getZero ()Lspace/kscience/kmath/nd/StructureND; - public fun getZero ()Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/viktor/ViktorStructureND; -} - -public class space/kscience/kmath/viktor/ViktorFieldOpsND : space/kscience/kmath/nd/FieldOpsND, space/kscience/kmath/operations/ExtendedFieldOps, space/kscience/kmath/operations/PowerOperations { - public static final field Companion Lspace/kscience/kmath/viktor/ViktorFieldOpsND$Companion; - public fun ()V public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; public fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public synthetic fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; public fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; public fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; public fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; + public synthetic fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; + public fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; public fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra; - public fun getElementAlgebra ()Lspace/kscience/kmath/operations/DoubleField; + public synthetic fun getElementContext ()Lspace/kscience/kmath/operations/Algebra; + public fun getElementContext ()Lspace/kscience/kmath/operations/DoubleField; public final fun getF64Buffer (Lspace/kscience/kmath/nd/StructureND;)Lorg/jetbrains/bio/viktor/F64Array; + public synthetic fun getOne ()Ljava/lang/Object; + public fun getOne ()Lspace/kscience/kmath/viktor/ViktorStructureND; + public fun getShape ()[I + public synthetic fun getZero ()Ljava/lang/Object; + public fun getZero ()Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; @@ -72,38 +43,26 @@ public class space/kscience/kmath/viktor/ViktorFieldOpsND : space/kscience/kmath public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun minus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; + public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; + public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun plus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; public fun plus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/viktor/ViktorStructureND; + public synthetic fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; + public fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public synthetic fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND; public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; public fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun times (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; public fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/viktor/ViktorStructureND; public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/viktor/ViktorStructureND; -} - -public final class space/kscience/kmath/viktor/ViktorFieldOpsND$Companion : space/kscience/kmath/viktor/ViktorFieldOpsND { -} - -public final class space/kscience/kmath/viktor/ViktorFieldOpsNDKt { - public static final fun ViktorFieldND ([I)Lspace/kscience/kmath/viktor/ViktorFieldND; - public static final fun getViktorAlgebra (Lspace/kscience/kmath/operations/DoubleField;)Lspace/kscience/kmath/viktor/ViktorFieldOpsND; - public static final fun viktorAlgebra (Lspace/kscience/kmath/operations/DoubleField;[I)Lspace/kscience/kmath/viktor/ViktorFieldND; } public final class space/kscience/kmath/viktor/ViktorStructureND : space/kscience/kmath/nd/MutableStructureND { @@ -112,12 +71,13 @@ public final class space/kscience/kmath/viktor/ViktorStructureND : space/kscienc public fun get ([I)Ljava/lang/Double; public synthetic fun get ([I)Ljava/lang/Object; public final fun getF64Buffer ()Lorg/jetbrains/bio/viktor/F64Array; - public fun getShape-IIYLAfE ()[I + public fun getShape ()[I public fun set ([ID)V public synthetic fun set ([ILjava/lang/Object;)V } public final class space/kscience/kmath/viktor/ViktorStructureNDKt { + public static final fun ViktorNDField ([I)Lspace/kscience/kmath/viktor/ViktorFieldND; public static final fun asStructure (Lorg/jetbrains/bio/viktor/F64Array;)Lspace/kscience/kmath/viktor/ViktorStructureND; } diff --git a/kmath-viktor/build.gradle.kts b/kmath-viktor/build.gradle.kts index 7a135f316..0d853dea7 100644 --- a/kmath-viktor/build.gradle.kts +++ b/kmath-viktor/build.gradle.kts @@ -1,14 +1,22 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import ru.mipt.npm.gradle.Maturity + plugins { - id("space.kscience.gradle.jvm") + kotlin("jvm") + id("ru.mipt.npm.gradle.common") } description = "Binding for https://github.com/JetBrains-Research/viktor" dependencies { api(project(":kmath-core")) - api("org.jetbrains.bio:viktor:1.2.0") + api("org.jetbrains.bio:viktor:1.0.1") } readme { - maturity = space.kscience.gradle.Maturity.DEVELOPMENT -} + maturity = Maturity.DEVELOPMENT +} \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt index 52dc1e192..bbf502faf 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt @@ -1,28 +1,24 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64FlatArray -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer @Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") -@JvmInline -public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { - override val size: Int - get() = flatArray.length +public class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { + public override val size: Int + get() = flatArray.size - override inline fun get(index: Int): Double = flatArray[index] + public override inline fun get(index: Int): Double = flatArray[index] - override inline fun set(index: Int, value: Double) { + public override inline fun set(index: Int, value: Double) { flatArray[index] = value } - override fun copy(): MutableBuffer = ViktorBuffer(flatArray.copy().flatten()) - override operator fun iterator(): Iterator = flatArray.data.iterator() - - override fun toString(): String = Buffer.toString(this) + public override fun copy(): MutableBuffer = ViktorBuffer(flatArray.copy().flatten()) + public override operator fun iterator(): Iterator = flatArray.data.iterator() } diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt deleted file mode 100644 index 8c7d6d199..000000000 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(PerformancePitfall::class) - -package space.kscience.kmath.viktor - -import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.UnsafeKMathAPI -import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedFieldOps -import space.kscience.kmath.operations.NumbersAddOps -import space.kscience.kmath.operations.PowerOperations - -@OptIn(UnstableKMathAPI::class, PerformancePitfall::class) -@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public open class ViktorFieldOpsND : - FieldOpsND, - ExtendedFieldOps>, - PowerOperations> { - - public val StructureND.f64Buffer: F64Array - get() = when (this) { - is ViktorStructureND -> this.f64Buffer - else -> structureND(shape) { this@f64Buffer[it] }.f64Buffer - } - - override val elementAlgebra: DoubleField get() = DoubleField - - @OptIn(UnsafeKMathAPI::class) - override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = - F64Array(*shape.asArray()).apply { - ColumnStrides(shape).asSequence().forEach { index -> - set(value = DoubleField.initializer(index), indices = index) - } - }.asStructure() - - override fun StructureND.unaryMinus(): StructureND = -1 * this - - @OptIn(UnsafeKMathAPI::class) - @PerformancePitfall - override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = - F64Array(*shape.asArray()).apply { - ColumnStrides(ShapeND(shape)).asSequence().forEach { index -> - set(value = DoubleField.transform(this@map[index]), indices = index) - } - }.asStructure() - - @OptIn(UnsafeKMathAPI::class) - @PerformancePitfall - override fun StructureND.mapIndexed( - transform: DoubleField.(index: IntArray, Double) -> Double, - ): ViktorStructureND = F64Array(*shape.asArray()).apply { - ColumnStrides(ShapeND(shape)).asSequence().forEach { index -> - set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index) - } - }.asStructure() - - @OptIn(UnsafeKMathAPI::class) - @PerformancePitfall - override fun zip( - left: StructureND, - right: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): ViktorStructureND { - require(left.shape.contentEquals(right.shape)) - return F64Array(*left.shape.asArray()).apply { - ColumnStrides(left.shape).asSequence().forEach { index -> - set(value = DoubleField.transform(left[index], right[index]), indices = index) - } - }.asStructure() - } - - override fun add(left: StructureND, right: StructureND): ViktorStructureND = - (left.f64Buffer + right.f64Buffer).asStructure() - - override fun scale(a: StructureND, value: Double): ViktorStructureND = - (a.f64Buffer * value).asStructure() - - override fun StructureND.plus(arg: StructureND): ViktorStructureND = - (f64Buffer + arg.f64Buffer).asStructure() - - override fun StructureND.minus(arg: StructureND): ViktorStructureND = - (f64Buffer - arg.f64Buffer).asStructure() - - override fun StructureND.times(k: Number): ViktorStructureND = - (f64Buffer * k.toDouble()).asStructure() - - override fun StructureND.plus(arg: Double): ViktorStructureND = - (f64Buffer.plus(arg)).asStructure() - - override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } - override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } - override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } - override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } - override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } - override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } - - override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } - - override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() - - override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() - - override fun sinh(arg: StructureND): ViktorStructureND = arg.map { sinh(it) } - - override fun cosh(arg: StructureND): ViktorStructureND = arg.map { cosh(it) } - - override fun asinh(arg: StructureND): ViktorStructureND = arg.map { asinh(it) } - - override fun acosh(arg: StructureND): ViktorStructureND = arg.map { acosh(it) } - - override fun atanh(arg: StructureND): ViktorStructureND = arg.map { atanh(it) } - - public companion object : ViktorFieldOpsND() -} - -public val DoubleField.viktorAlgebra: ViktorFieldOpsND get() = ViktorFieldOpsND - -@OptIn(UnstableKMathAPI::class) -public open class ViktorFieldND( - private val shapeAsArray: IntArray, -) : ViktorFieldOpsND(), FieldND, NumbersAddOps> { - - override val shape: ShapeND = ShapeND(shapeAsArray) - - - override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shapeAsArray).asStructure() } - override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shapeAsArray).asStructure() } - - override fun number(value: Number): ViktorStructureND = - F64Array.full(init = value.toDouble(), shape = shapeAsArray).asStructure() -} - -public fun DoubleField.viktorAlgebra(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) - -public fun ViktorFieldND(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt index 7c0c02086..dc1b45f5d 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt @@ -1,33 +1,124 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2021 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.PerformancePitfall -import space.kscience.kmath.nd.ColumnStrides -import space.kscience.kmath.nd.MutableStructureND -import space.kscience.kmath.nd.ShapeND +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.ScaleOperations @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructureND { - override val shape: ShapeND get() = ShapeND(f64Buffer.shape) + public override val shape: IntArray get() = f64Buffer.shape - @OptIn(PerformancePitfall::class) - override inline fun get(index: IntArray): Double = f64Buffer.get(*index) + public override inline fun get(index: IntArray): Double = f64Buffer.get(*index) - @OptIn(PerformancePitfall::class) - override inline fun set(index: IntArray, value: Double) { + public override inline fun set(index: IntArray, value: Double) { f64Buffer.set(*index, value = value) } - @PerformancePitfall - override fun elements(): Sequence> = - ColumnStrides(shape).asSequence().map { it to get(it) } + public override fun elements(): Sequence> = + DefaultStrides(shape).indices().map { it to get(it) } } public fun F64Array.asStructure(): ViktorStructureND = ViktorStructureND(this) +@OptIn(UnstableKMathAPI::class) +@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public class ViktorFieldND(public override val shape: IntArray) : FieldND, + NumbersAddOperations>, ExtendedField>, + ScaleOperations> { + public val StructureND.f64Buffer: F64Array + get() = when { + !shape.contentEquals(this@ViktorFieldND.shape) -> throw ShapeMismatchException( + this@ViktorFieldND.shape, + shape + ) + this is ViktorStructureND && this.f64Buffer.shape.contentEquals(this@ViktorFieldND.shape) -> this.f64Buffer + else -> produce { this@f64Buffer[it] }.f64Buffer + } + + public override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } + public override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } + + private val strides: Strides = DefaultStrides(shape) + + public override val elementContext: DoubleField get() = DoubleField + + public override fun produce(initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = + F64Array(*shape).apply { + this@ViktorFieldND.strides.indices().forEach { index -> + set(value = DoubleField.initializer(index), indices = index) + } + }.asStructure() + + public override fun StructureND.unaryMinus(): StructureND = -1 * this + + public override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = + F64Array(*this@ViktorFieldND.shape).apply { + this@ViktorFieldND.strides.indices().forEach { index -> + set(value = DoubleField.transform(this@map[index]), indices = index) + } + }.asStructure() + + public override fun StructureND.mapIndexed( + transform: DoubleField.(index: IntArray, Double) -> Double, + ): ViktorStructureND = F64Array(*this@ViktorFieldND.shape).apply { + this@ViktorFieldND.strides.indices().forEach { index -> + set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index) + } + }.asStructure() + + public override fun combine( + a: StructureND, + b: StructureND, + transform: DoubleField.(Double, Double) -> Double, + ): ViktorStructureND = F64Array(*shape).apply { + this@ViktorFieldND.strides.indices().forEach { index -> + set(value = DoubleField.transform(a[index], b[index]), indices = index) + } + }.asStructure() + + public override fun add(a: StructureND, b: StructureND): ViktorStructureND = + (a.f64Buffer + b.f64Buffer).asStructure() + + public override fun scale(a: StructureND, value: Double): ViktorStructureND = + (a.f64Buffer * value.toDouble()).asStructure() + + public override inline fun StructureND.plus(b: StructureND): ViktorStructureND = + (f64Buffer + b.f64Buffer).asStructure() + + public override inline fun StructureND.minus(b: StructureND): ViktorStructureND = + (f64Buffer - b.f64Buffer).asStructure() + + public override inline fun StructureND.times(k: Number): ViktorStructureND = + (f64Buffer * k.toDouble()).asStructure() + + public override inline fun StructureND.plus(arg: Double): ViktorStructureND = + (f64Buffer.plus(arg)).asStructure() + + public override fun number(value: Number): ViktorStructureND = + F64Array.full(init = value.toDouble(), shape = shape).asStructure() + + public override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } + public override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } + public override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } + public override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } + public override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } + public override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } + + public override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } + + public override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() + + public override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() +} + +public fun ViktorNDField(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) diff --git a/license/LICENSE.txt b/license/LICENSE.txt index d64569567..84b106a07 100644 --- a/license/LICENSE.txt +++ b/license/LICENSE.txt @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -187,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2018-2021 KMath contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/license/README.md b/license/README.md index 376321684..cfef3de79 100644 --- a/license/README.md +++ b/license/README.md @@ -51,3 +51,13 @@ The following modules contain third-party code and are incorporated into the KMa - Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt - License: Apache 2 ([cm](third_party/crng_license.txt)) - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation +- Path: + - License: Apache 2 ([cm](third_party/crng_license.txt)) + - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation + \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index f158f3444..babad3672 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,26 +1,33 @@ -rootProject.name = "kmath" - -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") - -dependencyResolutionManagement { - val toolsVersion: String by extra +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +pluginManagement { repositories { mavenLocal() - maven("https://repo.kotlin.link") mavenCentral() gradlePluginPortal() + maven("https://repo.kotlin.link") } - versionCatalogs { - create("spclibs") { - from("space.kscience:version-catalog:$toolsVersion") - } + val toolsVersion = "0.9.5-dev-2" + val kotlinVersion = "1.5.0-RC" + + plugins { + kotlin("multiplatform") version kotlinVersion + kotlin("jvm") version kotlinVersion + kotlin("plugin.allopen") version kotlinVersion + id("org.jetbrains.kotlinx.benchmark") version "0.3.0" + id("ru.mipt.npm.gradle.project") version toolsVersion + id("ru.mipt.npm.gradle.mpp") version toolsVersion + id("ru.mipt.npm.gradle.jvm") version toolsVersion } } +rootProject.name = "kmath" + include( - ":test-utils", ":kmath-memory", ":kmath-complex", ":kmath-core", @@ -29,9 +36,6 @@ include( ":kmath-histograms", ":kmath-commons", ":kmath-viktor", - ":kmath-multik", - ":kmath-tensorflow", - ":kmath-optimization", ":kmath-stat", ":kmath-nd4j", ":kmath-dimensions", @@ -40,10 +44,5 @@ include( ":kmath-ast", ":kmath-ejml", ":kmath-kotlingrad", - ":kmath-tensors", - ":kmath-jupyter", - ":kmath-symja", - ":kmath-jafama", - ":examples", - ":benchmarks", + ":examples" ) diff --git a/test-utils/README.md b/test-utils/README.md deleted file mode 100644 index 6ff8b98e8..000000000 --- a/test-utils/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Module test-utils - - - diff --git a/test-utils/api/test-utils.api b/test-utils/api/test-utils.api deleted file mode 100644 index fc812a9a6..000000000 --- a/test-utils/api/test-utils.api +++ /dev/null @@ -1,32 +0,0 @@ -public final class space/kscience/kmath/testutils/AssertsKt { - public static final fun assertBufferEquals (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;D)V - public static synthetic fun assertBufferEquals$default (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;DILjava/lang/Object;)V -} - -public final class space/kscience/kmath/testutils/BufferEqualityKt { - public static final fun contentEquals-2c9zdjM ([D[D)Z - public static final fun contentEqualsArray ([D[D)Z - public static final fun contentEqualsBuffer ([D[D)Z -} - -public final class space/kscience/kmath/testutils/FieldVerifier : space/kscience/kmath/testutils/RingVerifier { - public fun (Lspace/kscience/kmath/operations/Field;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Number;)V - public fun verify ()V -} - -public class space/kscience/kmath/testutils/RingVerifier : space/kscience/kmath/testutils/SpaceVerifier { - public fun (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Number;)V - public fun verify ()V -} - -public class space/kscience/kmath/testutils/SpaceVerifier : space/kscience/kmath/testutils/AlgebraicVerifier { - public fun (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Number;)V - public final fun getA ()Ljava/lang/Object; - public synthetic fun getAlgebra ()Lspace/kscience/kmath/operations/Algebra; - public fun getAlgebra ()Lspace/kscience/kmath/operations/Ring; - public final fun getB ()Ljava/lang/Object; - public final fun getC ()Ljava/lang/Object; - public final fun getX ()Ljava/lang/Number; - public fun verify ()V -} - diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts deleted file mode 100644 index b03059eaf..000000000 --- a/test-utils/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - id("space.kscience.gradle.mpp") -} - -kscience{ - jvm() - js() - native() - wasm() -} - -kotlin.sourceSets { - commonMain { - dependencies { - api(projects.kmath.kmathCore) - api(kotlin("test")) - } - } -} diff --git a/test-utils/src/commonMain/kotlin/asserts.kt b/test-utils/src/commonMain/kotlin/asserts.kt deleted file mode 100644 index 8ddce517c..000000000 --- a/test-utils/src/commonMain/kotlin/asserts.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.testutils - -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices -import kotlin.test.assertEquals -import kotlin.test.fail - -public fun assertBufferEquals(expected: Buffer, result: Buffer, tolerance: Double = 1e-4) { - if (expected.size != result.size) { - fail("Expected size is ${expected.size}, but the result size is ${result.size}") - } - expected.indices.forEach { - assertEquals(expected[it], result[it], tolerance) - } -} \ No newline at end of file diff --git a/test-utils/src/commonMain/kotlin/bufferEquality.kt b/test-utils/src/commonMain/kotlin/bufferEquality.kt deleted file mode 100644 index 9e4d9ec22..000000000 --- a/test-utils/src/commonMain/kotlin/bufferEquality.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2018-2022 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.testutils - -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.jvm.JvmName - -/** - * Simplified [DoubleBuffer] to array comparison - */ -public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles) - -@JvmName("contentEqualsArray") -public infix fun DoubleBuffer.contentEquals(otherArray: DoubleArray): Boolean = array.contentEquals(otherArray) - -@JvmName("contentEqualsBuffer") -public infix fun DoubleBuffer.contentEquals(otherBuffer: DoubleBuffer): Boolean = array.contentEquals(otherBuffer.array) \ No newline at end of file