Feature/tensors performance #497
27
.github/workflows/build.yml
vendored
27
.github/workflows/build.yml
vendored
@ -13,25 +13,13 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: DeLaGuardo/setup-graalvm@4.0
|
||||
- uses: actions/checkout@v3.0.0
|
||||
- uses: actions/setup-java@v3.0.0
|
||||
with:
|
||||
graalvm: 21.2.0
|
||||
java: java11
|
||||
arch: amd64
|
||||
- name: Cache gradle
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
java-version: 11
|
||||
distribution: liberica
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3.0.1
|
||||
with:
|
||||
path: ~/.konan
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
@ -39,5 +27,6 @@ jobs:
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Gradle Wrapper Validation
|
||||
uses: gradle/wrapper-validation-action@v1.0.4
|
||||
- name: Build
|
||||
run: ./gradlew build --build-cache --no-daemon --stacktrace
|
||||
- uses: gradle/gradle-build-action@v2.1.5
|
||||
with:
|
||||
arguments: build
|
||||
|
25
.github/workflows/pages.yml
vendored
25
.github/workflows/pages.yml
vendored
@ -1,28 +1,31 @@
|
||||
name: Dokka publication
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [ created ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: DeLaGuardo/setup-graalvm@4.0
|
||||
- uses: actions/checkout@v3.0.0
|
||||
- uses: actions/setup-java@v3.0.0
|
||||
with:
|
||||
graalvm: 21.2.0
|
||||
java: java11
|
||||
arch: amd64
|
||||
- uses: actions/cache@v2
|
||||
java-version: 11
|
||||
distribution: liberica
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v3.0.1
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
path: ~/.konan
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- run: ./gradlew dokkaHtmlMultiModule --build-cache --no-daemon --no-parallel --stacktrace
|
||||
- uses: JamesIves/github-pages-deploy-action@4.1.0
|
||||
- uses: gradle/gradle-build-action@v2.1.5
|
||||
with:
|
||||
arguments: dokkaHtmlMultiModule --no-parallel
|
||||
- uses: JamesIves/github-pages-deploy-action@v4.3.0
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: build/dokka/htmlMultiModule
|
||||
|
52
.github/workflows/publish.yml
vendored
52
.github/workflows/publish.yml
vendored
@ -14,42 +14,38 @@ jobs:
|
||||
os: [ macOS-latest, windows-latest ]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: DeLaGuardo/setup-graalvm@4.0
|
||||
- uses: actions/checkout@v3.0.0
|
||||
- uses: actions/setup-java@v3.0.0
|
||||
with:
|
||||
graalvm: 21.2.0
|
||||
java: java11
|
||||
arch: amd64
|
||||
- name: Cache gradle
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
java-version: 11
|
||||
distribution: liberica
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3.0.1
|
||||
with:
|
||||
path: ~/.konan
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Gradle Wrapper Validation
|
||||
uses: gradle/wrapper-validation-action@v1.0.4
|
||||
- uses: gradle/wrapper-validation-action@v1.0.4
|
||||
- name: Publish Windows Artifacts
|
||||
if: matrix.os == 'windows-latest'
|
||||
shell: cmd
|
||||
run: >
|
||||
./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true
|
||||
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
||||
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}
|
||||
uses: gradle/gradle-build-action@v2.1.5
|
||||
with:
|
||||
arguments: |
|
||||
releaseAll
|
||||
-Ppublishing.enabled=true
|
||||
-Ppublishing.sonatype=false
|
||||
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
||||
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}
|
||||
- name: Publish Mac Artifacts
|
||||
if: matrix.os == 'macOS-latest'
|
||||
run: >
|
||||
./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true -Ppublishing.platform=macosX64
|
||||
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
||||
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}
|
||||
uses: gradle/gradle-build-action@v2.1.5
|
||||
with:
|
||||
arguments: |
|
||||
releaseMacosX64
|
||||
releaseIosArm64
|
||||
releaseIosX64
|
||||
-Ppublishing.enabled=true
|
||||
-Ppublishing.sonatype=false
|
||||
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
||||
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,3 +19,4 @@ out/
|
||||
|
||||
!/.idea/copyright/
|
||||
!/.idea/scopes/
|
||||
/kotlin-js-store/yarn.lock
|
||||
|
36
CHANGELOG.md
36
CHANGELOG.md
@ -2,6 +2,19 @@
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
|
||||
### Fixed
|
||||
|
||||
### Security
|
||||
|
||||
## [0.3.0]
|
||||
### Added
|
||||
- `ScaleOperations` interface
|
||||
- `Field` extends `ScaleOperations`
|
||||
- Basic integration API
|
||||
@ -19,6 +32,12 @@
|
||||
- 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
|
||||
- Exponential operations merged with hyperbolic functions
|
||||
@ -48,10 +67,15 @@
|
||||
- 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`
|
||||
|
||||
|
||||
### Deprecated
|
||||
- Specialized `DoubleBufferAlgebra`
|
||||
|
||||
|
||||
### Removed
|
||||
- Nearest in Domain. To be implemented in geometry package.
|
||||
- Number multiplication and division in main Algebra chain
|
||||
@ -62,10 +86,12 @@
|
||||
- Second generic from DifferentiableExpression
|
||||
- Algebra elements are completely removed. Use algebra contexts instead.
|
||||
|
||||
|
||||
### Fixed
|
||||
- Ring inherits RingOperations, not GroupOperations
|
||||
- Univariate histogram filling
|
||||
|
||||
|
||||
### Security
|
||||
|
||||
## [0.2.0]
|
||||
@ -88,6 +114,7 @@
|
||||
- New `MatrixFeature` interfaces for matrix decompositions
|
||||
- Basic Quaternion vector support in `kmath-complex`.
|
||||
|
||||
|
||||
### Changed
|
||||
- Package changed from `scientifik` to `space.kscience`
|
||||
- Gradle version: 6.6 -> 6.8.2
|
||||
@ -112,7 +139,6 @@
|
||||
- `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.
|
||||
@ -122,13 +148,11 @@
|
||||
- `Real` class
|
||||
- StructureND identity and equals
|
||||
|
||||
|
||||
### Fixed
|
||||
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
||||
|
||||
### Security
|
||||
|
||||
## [0.1.4]
|
||||
|
||||
### Added
|
||||
- Functional Expressions API
|
||||
- Mathematical Syntax Tree, its interpreter and API
|
||||
@ -146,6 +170,7 @@
|
||||
- Full hyperbolic functions support and default implementations within `ExtendedField`
|
||||
- Norm support for `Complex`
|
||||
|
||||
|
||||
### Changed
|
||||
- `readAsMemory` now has `throws IOException` in JVM signature.
|
||||
- Several functions taking functional types were made `inline`.
|
||||
@ -157,9 +182,10 @@
|
||||
- Gradle version: 6.3 -> 6.6
|
||||
- Moved probability distributions to commons-rng and to `kmath-prob`
|
||||
|
||||
|
||||
### Fixed
|
||||
- Missing copy method in Memory implementation on JS (https://github.com/mipt-npm/kmath/pull/106)
|
||||
- D3.dim value in `kmath-dimensions`
|
||||
- Multiplication in integer rings in `kmath-core` (https://github.com/mipt-npm/kmath/pull/101)
|
||||
- Commons RNG compatibility (https://github.com/mipt-npm/kmath/issues/93)
|
||||
- Multiplication of BigInt by scalar
|
||||
- Multiplication of BigInt by scalar
|
80
README.md
80
README.md
@ -52,21 +52,18 @@ module definitions below. The module stability could have the following levels:
|
||||
|
||||
## Modules
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [benchmarks](benchmarks)
|
||||
### [benchmarks](benchmarks)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
<hr/>
|
||||
|
||||
* ### [examples](examples)
|
||||
### [examples](examples)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-ast](kmath-ast)
|
||||
### [kmath-ast](kmath-ast)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
@ -77,15 +74,13 @@ module definitions below. The module stability could have the following levels:
|
||||
> - [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
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-commons](kmath-commons)
|
||||
### [kmath-commons](kmath-commons)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-complex](kmath-complex)
|
||||
### [kmath-complex](kmath-complex)
|
||||
> Complex numbers and quaternions.
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
@ -94,9 +89,8 @@ module definitions below. The module stability could have the following levels:
|
||||
> - [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
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-core](kmath-core)
|
||||
### [kmath-core](kmath-core)
|
||||
> Core classes, algebra definitions, basic linear algebra
|
||||
>
|
||||
> **Maturity**: DEVELOPMENT
|
||||
@ -112,21 +106,18 @@ 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
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-coroutines](kmath-coroutines)
|
||||
### [kmath-coroutines](kmath-coroutines)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-dimensions](kmath-dimensions)
|
||||
### [kmath-dimensions](kmath-dimensions)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-ejml](kmath-ejml)
|
||||
### [kmath-ejml](kmath-ejml)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
@ -136,9 +127,8 @@ performance calculations to code generation.
|
||||
> - [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.
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-for-real](kmath-for-real)
|
||||
### [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.
|
||||
@ -150,9 +140,8 @@ 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
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-functions](kmath-functions)
|
||||
### [kmath-functions](kmath-functions)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
@ -164,21 +153,18 @@ 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
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-geometry](kmath-geometry)
|
||||
### [kmath-geometry](kmath-geometry)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-histograms](kmath-histograms)
|
||||
### [kmath-histograms](kmath-histograms)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-jafama](kmath-jafama)
|
||||
### [kmath-jafama](kmath-jafama)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
@ -186,15 +172,13 @@ One can still use generic algebras though.
|
||||
> **Features:**
|
||||
> - [jafama-double](kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-jupyter](kmath-jupyter)
|
||||
### [kmath-jupyter](kmath-jupyter)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-kotlingrad](kmath-kotlingrad)
|
||||
### [kmath-kotlingrad](kmath-kotlingrad)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
@ -203,21 +187,18 @@ One can still use generic algebras though.
|
||||
> - [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
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-memory](kmath-memory)
|
||||
### [kmath-memory](kmath-memory)
|
||||
> An API and basic implementation for arranging objects in a continuous memory block.
|
||||
>
|
||||
> **Maturity**: DEVELOPMENT
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-multik](kmath-multik)
|
||||
### [kmath-multik](kmath-multik)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-nd4j](kmath-nd4j)
|
||||
### [kmath-nd4j](kmath-nd4j)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
@ -227,33 +208,28 @@ 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
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-optimization](kmath-optimization)
|
||||
### [kmath-optimization](kmath-optimization)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-stat](kmath-stat)
|
||||
### [kmath-stat](kmath-stat)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-symja](kmath-symja)
|
||||
### [kmath-symja](kmath-symja)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-tensorflow](kmath-tensorflow)
|
||||
### [kmath-tensorflow](kmath-tensorflow)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-tensors](kmath-tensors)
|
||||
### [kmath-tensors](kmath-tensors)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
@ -263,13 +239,11 @@ One can still use generic algebras though.
|
||||
> - [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.
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-viktor](kmath-viktor)
|
||||
### [kmath-viktor](kmath-viktor)
|
||||
>
|
||||
>
|
||||
> **Maturity**: DEVELOPMENT
|
||||
<hr/>
|
||||
|
||||
|
||||
## Multi-platform support
|
||||
@ -308,8 +282,8 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api("space.kscience:kmath-core:0.3.0-dev-17")
|
||||
// api("space.kscience:kmath-core-jvm:0.3.0-dev-17") for jvm-specific version
|
||||
api("space.kscience:kmath-core:$version")
|
||||
// api("space.kscience:kmath-core-jvm:$version") for jvm-specific version
|
||||
}
|
||||
```
|
||||
|
||||
|
4
benchmarks/README.md
Normal file
4
benchmarks/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module benchmarks
|
||||
|
||||
|
||||
|
@ -84,6 +84,11 @@ benchmark {
|
||||
iterationTimeUnit = "ms"
|
||||
}
|
||||
|
||||
configurations.register("svd") {
|
||||
commonConfiguration()
|
||||
include("SVDBenchmark")
|
||||
}
|
||||
|
||||
configurations.register("buffer") {
|
||||
commonConfiguration()
|
||||
include("BufferBenchmark")
|
||||
@ -155,7 +160,7 @@ kotlin.sourceSets.all {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xlambdas=indy"
|
||||
|
@ -15,8 +15,10 @@ import space.kscience.kmath.linear.invoke
|
||||
import space.kscience.kmath.linear.linearSpace
|
||||
import space.kscience.kmath.multik.multikAlgebra
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.tensorflow.produceWithTF
|
||||
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
|
||||
import space.kscience.kmath.tensors.core.tensorAlgebra
|
||||
import kotlin.random.Random
|
||||
|
||||
@ -90,4 +92,9 @@ internal class DotBenchmark {
|
||||
fun doubleDot(blackhole: Blackhole) = with(DoubleField.linearSpace) {
|
||||
blackhole.consume(matrix1 dot matrix2)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun doubleTensorDot(blackhole: Blackhole) = DoubleTensorAlgebra.invoke {
|
||||
blackhole.consume(matrix1 dot matrix2)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this 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.ejml.UtilEjml.assertTrue
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.diagonalEmbedding
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.dot
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.eq
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.svdGolubKahan
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.transpose
|
||||
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
|
||||
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.svdPowerMethod
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
class SVDBenchmark {
|
||||
companion object {
|
||||
val tensorSmall = DoubleTensorAlgebra.randomNormal(intArrayOf(5, 5), 0)
|
||||
val tensorMedium = DoubleTensorAlgebra.randomNormal(intArrayOf(10, 10), 0)
|
||||
val tensorLarge = DoubleTensorAlgebra.randomNormal(intArrayOf(50, 50), 0)
|
||||
val tensorVeryLarge = DoubleTensorAlgebra.randomNormal(intArrayOf(100, 100), 0)
|
||||
val epsilon = 1e-9
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdPowerMethodSmall(blackhole: Blackhole) {
|
||||
val svd = tensorSmall.svdPowerMethod()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorSmall, epsilon))
|
||||
blackhole.consume(
|
||||
tensorSmall.svdPowerMethod()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdPowerMethodMedium(blackhole: Blackhole) {
|
||||
val svd = tensorMedium.svdPowerMethod()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorMedium, epsilon))
|
||||
blackhole.consume(
|
||||
tensorMedium.svdPowerMethod()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdPowerMethodLarge(blackhole: Blackhole) {
|
||||
val svd = tensorLarge.svdPowerMethod()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorLarge, epsilon))
|
||||
blackhole.consume(
|
||||
tensorLarge.svdPowerMethod()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdPowerMethodVeryLarge(blackhole: Blackhole) {
|
||||
val svd = tensorVeryLarge.svdPowerMethod()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorVeryLarge, epsilon))
|
||||
blackhole.consume(
|
||||
tensorVeryLarge.svdPowerMethod()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdGolubKahanSmall(blackhole: Blackhole) {
|
||||
val svd = tensorSmall.svdGolubKahan()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorSmall, epsilon))
|
||||
blackhole.consume(
|
||||
tensorSmall.svdGolubKahan()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdGolubKahanMedium(blackhole: Blackhole) {
|
||||
val svd = tensorMedium.svdGolubKahan()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorMedium, epsilon))
|
||||
blackhole.consume(
|
||||
tensorMedium.svdGolubKahan()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdGolubKahanLarge(blackhole: Blackhole) {
|
||||
val svd = tensorLarge.svdGolubKahan()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorLarge, epsilon))
|
||||
blackhole.consume(
|
||||
tensorLarge.svdGolubKahan()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdGolubKahanVeryLarge(blackhole: Blackhole) {
|
||||
val svd = tensorVeryLarge.svdGolubKahan()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorVeryLarge, epsilon))
|
||||
blackhole.consume(
|
||||
tensorVeryLarge.svdGolubKahan()
|
||||
)
|
||||
}
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.project")
|
||||
id("org.jetbrains.kotlinx.kover") version "0.5.0-RC"
|
||||
id("org.jetbrains.kotlinx.kover") version "0.5.0"
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
group = "space.kscience"
|
||||
version = "0.3.0-dev-19"
|
||||
version = "0.3.0"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
@ -55,7 +56,7 @@ subprojects {
|
||||
readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
||||
|
||||
ksciencePublish {
|
||||
github("kmath")
|
||||
github("kmath", addToRelease = false)
|
||||
space()
|
||||
sonatype()
|
||||
}
|
||||
|
@ -1,20 +1,21 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
`version-catalog`
|
||||
alias(npmlibs.plugins.kotlin.plugin.serialization)
|
||||
alias(miptNpmLibs.plugins.kotlin.plugin.serialization)
|
||||
}
|
||||
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
val toolsVersion: String by extra
|
||||
val kotlinVersion = npmlibs.versions.kotlin.asProvider().get()
|
||||
val benchmarksVersion = "0.4.2"
|
||||
val kotlinVersion = miptNpmLibs.versions.kotlin.asProvider().get()
|
||||
val benchmarksVersion = miptNpmLibs.versions.kotlinx.benchmark.get()
|
||||
|
||||
dependencies {
|
||||
api("ru.mipt.npm:gradle-tools:$toolsVersion")
|
||||
@ -22,7 +23,7 @@ dependencies {
|
||||
api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion")
|
||||
api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
|
||||
//to be used inside build-script only
|
||||
implementation(npmlibs.kotlinx.serialization.json)
|
||||
implementation(miptNpmLibs.kotlinx.serialization.json)
|
||||
}
|
||||
|
||||
kotlin.sourceSets.all {
|
||||
|
@ -4,11 +4,4 @@
|
||||
#
|
||||
|
||||
kotlin.code.style=official
|
||||
kotlin.mpp.stability.nowarn=true
|
||||
|
||||
kotlin.jupyter.add.scanner=false
|
||||
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
toolsVersion=0.10.9-kotlin-1.6.10
|
||||
toolsVersion=0.11.2-kotlin-1.6.10
|
||||
|
@ -3,21 +3,20 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
|
||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||
enableFeaturePreview("VERSION_CATALOGS")
|
||||
|
||||
dependencyResolutionManagement {
|
||||
|
||||
val toolsVersion: String by extra
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
versionCatalogs {
|
||||
create("npmlibs") {
|
||||
create("miptNpmLibs") {
|
||||
from("ru.mipt.npm:version-catalog:$toolsVersion")
|
||||
}
|
||||
}
|
||||
|
2
docs/templates/README-TEMPLATE.md
vendored
2
docs/templates/README-TEMPLATE.md
vendored
@ -52,7 +52,7 @@ module definitions below. The module stability could have the following levels:
|
||||
|
||||
## Modules
|
||||
|
||||
$modules
|
||||
${modules}
|
||||
|
||||
## Multi-platform support
|
||||
|
||||
|
4
examples/README.md
Normal file
4
examples/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module examples
|
||||
|
||||
|
||||
|
@ -58,7 +58,7 @@ kotlin.sourceSets.all {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy"
|
||||
|
@ -13,7 +13,7 @@ import kotlin.math.pow
|
||||
|
||||
fun main() {
|
||||
//Define a function
|
||||
val function: UnivariateFunction<Double> = { x -> 3 * x.pow(2) + 2 * x + 1 }
|
||||
val function: Function1D<Double> = { 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)
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.interpolation.SplineInterpolator
|
||||
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
|
||||
@ -18,7 +18,7 @@ import space.kscience.plotly.scatter
|
||||
|
||||
@OptIn(UnstablePlotlyAPI::class)
|
||||
fun main() {
|
||||
val function: UnivariateFunction<Double> = { x ->
|
||||
val function: Function1D<Double> = { x ->
|
||||
if (x in 30.0..50.0) {
|
||||
1.0
|
||||
} else {
|
||||
@ -28,7 +28,7 @@ fun main() {
|
||||
val xs = 0.0..100.0 step 0.5
|
||||
val ys = xs.map(function)
|
||||
|
||||
val polynomial: PiecewisePolynomial<Double> = SplineInterpolator.double.interpolatePolynomials(xs, ys)
|
||||
val polynomial: PiecewisePolynomial<Double> = DoubleField.splineInterpolator.interpolatePolynomials(xs, ys)
|
||||
|
||||
val polyFunction = polynomial.asFunction(DoubleField, 0.0)
|
||||
|
||||
|
@ -1,65 +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.tensors
|
||||
|
||||
import space.kscience.kmath.linear.transpose
|
||||
import space.kscience.kmath.misc.PerformancePitfall
|
||||
import space.kscience.kmath.nd.MutableStructure2D
|
||||
import space.kscience.kmath.nd.Structure2D
|
||||
import space.kscience.kmath.nd.as2D
|
||||
import space.kscience.kmath.tensors.core.*
|
||||
import space.kscience.kmath.tensors.core.tensorAlgebra
|
||||
import kotlin.math.*
|
||||
|
||||
fun MutableStructure2D<Double>.print() {
|
||||
val n = this.shape.component1()
|
||||
val m = this.shape.component2()
|
||||
for (i in 0 until n) {
|
||||
for (j in 0 until m) {
|
||||
val x = (this[i, j] * 100).roundToInt() / 100.0
|
||||
print("$x ")
|
||||
}
|
||||
println()
|
||||
}
|
||||
println("______________")
|
||||
}
|
||||
|
||||
@OptIn(PerformancePitfall::class)
|
||||
fun main(): Unit = Double.tensorAlgebra.withBroadcast {
|
||||
val shape = intArrayOf(5, 3)
|
||||
val buffer = doubleArrayOf(
|
||||
1.000000, 2.000000, 3.000000,
|
||||
2.000000, 3.000000, 4.000000,
|
||||
3.000000, 4.000000, 5.000000,
|
||||
4.000000, 5.000000, 6.000000,
|
||||
5.000000, 6.000000, 7.000000
|
||||
)
|
||||
val buffer2 = doubleArrayOf(
|
||||
0.000000, 0.000000, 0.000000,
|
||||
0.000000, 0.000000, 0.000000,
|
||||
0.000000, 0.000000, 0.000000
|
||||
)
|
||||
val tensor = fromArray(shape, buffer).as2D()
|
||||
val v = fromArray(intArrayOf(3, 3), buffer2).as2D()
|
||||
val w_shape = intArrayOf(3, 1)
|
||||
var w_buffer = doubleArrayOf(0.000000)
|
||||
for (i in 0 until 3 - 1) {
|
||||
w_buffer += doubleArrayOf(0.000000)
|
||||
}
|
||||
val w = BroadcastDoubleTensorAlgebra.fromArray(w_shape, w_buffer).as2D()
|
||||
tensor.print()
|
||||
var ans = Pair(w, v)
|
||||
tensor.svdGolabKahan(v, w)
|
||||
|
||||
println("u")
|
||||
tensor.print()
|
||||
println("w")
|
||||
w.print()
|
||||
println("v")
|
||||
v.print()
|
||||
|
||||
|
||||
}
|
@ -1,325 +0,0 @@
|
||||
package space.kscience.kmath.tensors
|
||||
|
||||
import space.kscience.kmath.nd.*
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sqrt
|
||||
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
fun pythag(a: Double, b: Double): Double {
|
||||
val at: Double = abs(a)
|
||||
val bt: Double = abs(b)
|
||||
val ct: Double
|
||||
val result: Double
|
||||
if (at > bt) {
|
||||
ct = bt / at
|
||||
result = at * sqrt(1.0 + ct * ct)
|
||||
} else if (bt > 0.0) {
|
||||
ct = at / bt
|
||||
result = bt * sqrt(1.0 + ct * ct)
|
||||
} else result = 0.0
|
||||
return result
|
||||
}
|
||||
|
||||
fun SIGN(a: Double, b: Double): Double {
|
||||
if (b >= 0.0)
|
||||
return abs(a)
|
||||
else
|
||||
return -abs(a)
|
||||
}
|
||||
|
||||
// matrix v is not transposed at the output
|
||||
|
||||
internal fun MutableStructure2D<Double>.svdGolabKahan(v: MutableStructure2D<Double>, w: MutableStructure2D<Double>) {
|
||||
val shape = this.shape
|
||||
val m = shape.component1()
|
||||
val n = shape.component2()
|
||||
var f = 0.0
|
||||
val rv1 = DoubleArray(n)
|
||||
var s = 0.0
|
||||
var scale = 0.0
|
||||
var anorm = 0.0
|
||||
var g = 0.0
|
||||
var l = 0
|
||||
for (i in 0 until n) {
|
||||
/* left-hand reduction */
|
||||
l = i + 1
|
||||
rv1[i] = scale * g
|
||||
g = 0.0
|
||||
s = 0.0
|
||||
scale = 0.0
|
||||
if (i < m) {
|
||||
for (k in i until m) {
|
||||
scale += abs(this[k, i]);
|
||||
}
|
||||
if (scale != 0.0) {
|
||||
for (k in i until m) {
|
||||
this[k, i] = (this[k, i] / scale)
|
||||
s += this[k, i] * this[k, i]
|
||||
}
|
||||
f = this[i, i]
|
||||
if (f >= 0) {
|
||||
g = (-1) * abs(sqrt(s))
|
||||
} else {
|
||||
g = abs(sqrt(s))
|
||||
}
|
||||
val h = f * g - s
|
||||
this[i, i] = f - g
|
||||
if (i != n - 1) {
|
||||
for (j in l until n) {
|
||||
s = 0.0
|
||||
for (k in i until m) {
|
||||
s += this[k, i] * this[k, j]
|
||||
}
|
||||
f = s / h
|
||||
for (k in i until m) {
|
||||
this[k, j] += f * this[k, i]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k in i until m) {
|
||||
this[k, i] = this[k, i] * scale
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w[i, 0] = scale * g
|
||||
/* right-hand reduction */
|
||||
g = 0.0
|
||||
s = 0.0
|
||||
scale = 0.0
|
||||
if (i < m && i != n - 1) {
|
||||
for (k in l until n) {
|
||||
scale += abs(this[i, k])
|
||||
}
|
||||
if (scale != 0.0) {
|
||||
for (k in l until n) {
|
||||
this[i, k] = this[i, k] / scale
|
||||
s += this[i, k] * this[i, k]
|
||||
}
|
||||
f = this[i, l]
|
||||
if (f >= 0) {
|
||||
g = (-1) * abs(sqrt(s))
|
||||
} else {
|
||||
g = abs(sqrt(s))
|
||||
}
|
||||
val h = f * g - s
|
||||
this[i, l] = f - g
|
||||
for (k in l until n) {
|
||||
rv1[k] = this[i, k] / h
|
||||
}
|
||||
if (i != m - 1) {
|
||||
for (j in l until m) {
|
||||
s = 0.0
|
||||
for (k in l until n) {
|
||||
s += this[j, k] * this[i, k]
|
||||
}
|
||||
for (k in l until n) {
|
||||
this[j, k] += s * rv1[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k in l until n) {
|
||||
this[i, k] = this[i, k] * scale
|
||||
}
|
||||
}
|
||||
}
|
||||
anorm = max(anorm, (abs(w[i, 0]) + abs(rv1[i])));
|
||||
}
|
||||
|
||||
for (i in n - 1 downTo 0) {
|
||||
if (i < n - 1) {
|
||||
if (g != 0.0) {
|
||||
for (j in l until n) {
|
||||
v[j, i] = (this[i, j] / this[i, l]) / g
|
||||
}
|
||||
for (j in l until n) {
|
||||
s = 0.0
|
||||
for (k in l until n)
|
||||
s += this[i, k] * v[k, j]
|
||||
for (k in l until n)
|
||||
v[k, j] += s * v[k, i]
|
||||
}
|
||||
}
|
||||
for (j in l until n) {
|
||||
v[i, j] = 0.0
|
||||
v[j, i] = 0.0
|
||||
}
|
||||
}
|
||||
v[i, i] = 1.0
|
||||
g = rv1[i]
|
||||
l = i
|
||||
}
|
||||
|
||||
// до этого момента все правильно считается
|
||||
// дальше - нет
|
||||
|
||||
for (i in min(n, m) - 1 downTo 0) {
|
||||
l = i + 1
|
||||
g = w[i, 0]
|
||||
for (j in l until n) {
|
||||
this[i, j] = 0.0
|
||||
}
|
||||
if (g != 0.0) {
|
||||
// !!!!! вот тут деление на почти ноль
|
||||
g = 1.0 / g
|
||||
for (j in l until n) {
|
||||
s = 0.0
|
||||
for (k in l until m) {
|
||||
s += this[k, i] * this[k, j]
|
||||
}
|
||||
f = (s / this[i, i]) * g
|
||||
for (k in i until m) {
|
||||
this[k, j] += f * this[k, i]
|
||||
}
|
||||
}
|
||||
for (j in i until m) {
|
||||
this[j, i] *= g
|
||||
}
|
||||
} else {
|
||||
for (j in i until m) {
|
||||
this[j, i] = 0.0
|
||||
}
|
||||
}
|
||||
this[i, i] += 1.0
|
||||
}
|
||||
|
||||
// println("matrix")
|
||||
// this.print()
|
||||
// тут матрица должна выглядеть так:
|
||||
// 0.134840 -0.762770 0.522117
|
||||
// -0.269680 -0.476731 -0.245388
|
||||
// -0.404520 -0.190693 -0.527383
|
||||
// -0.539360 0.095346 -0.297540
|
||||
// -0.674200 0.381385 0.548193
|
||||
|
||||
this[0, 2] = 0.522117
|
||||
this[1, 2] = -0.245388
|
||||
this[2, 2] = -0.527383
|
||||
this[3, 2] = -0.297540
|
||||
this[4, 2] = 0.548193
|
||||
|
||||
// задала правильные значения, чтобы проверить правильность кода дальше
|
||||
// дальше - все корректно
|
||||
|
||||
var flag = 0
|
||||
var nm = 0
|
||||
var c = 0.0
|
||||
var h = 0.0
|
||||
var y = 0.0
|
||||
var z = 0.0
|
||||
var x = 0.0
|
||||
for (k in n - 1 downTo 0) {
|
||||
for (its in 1 until 30) {
|
||||
flag = 1
|
||||
for (newl in k downTo 0) {
|
||||
nm = newl - 1
|
||||
if (abs(rv1[newl]) + anorm == anorm) {
|
||||
flag = 0
|
||||
l = newl
|
||||
break
|
||||
}
|
||||
if (abs(w[nm, 0]) + anorm == anorm) {
|
||||
l = newl
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (flag != 0) {
|
||||
c = 0.0
|
||||
s = 1.0
|
||||
for (i in l until k) {
|
||||
f = s * rv1[i]
|
||||
rv1[i] = c * rv1[i]
|
||||
if (abs(f) + anorm == anorm) {
|
||||
break
|
||||
}
|
||||
h = pythag(f, g)
|
||||
w[i, 0] = h
|
||||
h = 1.0 / h
|
||||
c = g * h
|
||||
s = (-f) * h
|
||||
for (j in 0 until m) {
|
||||
y = this[j, nm]
|
||||
z = this[j, i]
|
||||
this[j, nm] = y * c + z * s
|
||||
this[j, i] = z * c - y * s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
z = w[k, 0]
|
||||
if (l == k) {
|
||||
if (z < 0.0) {
|
||||
w[k, 0] = -z
|
||||
for (j in 0 until n)
|
||||
v[j, k] = -v[j, k]
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// надо придумать, что сделать - выкинуть ошибку?
|
||||
// if (its == 30) {
|
||||
// return
|
||||
// }
|
||||
|
||||
x = w[l, 0]
|
||||
nm = k - 1
|
||||
y = w[nm, 0]
|
||||
g = rv1[nm]
|
||||
h = rv1[k]
|
||||
f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y)
|
||||
g = pythag(f, 1.0)
|
||||
f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x
|
||||
c = 1.0
|
||||
s = 1.0
|
||||
|
||||
var i = 0
|
||||
for (j in l until nm + 1) {
|
||||
i = j + 1
|
||||
g = rv1[i]
|
||||
y = w[i, 0]
|
||||
h = s * g
|
||||
g = c * g
|
||||
z = pythag(f, h)
|
||||
rv1[j] = z
|
||||
c = f / z
|
||||
s = h / z
|
||||
f = x * c + g * s
|
||||
g = g * c - x * s
|
||||
h = y * s
|
||||
y *= c
|
||||
|
||||
for (jj in 0 until n) {
|
||||
x = v[jj, j];
|
||||
z = v[jj, i];
|
||||
v[jj, j] = x * c + z * s;
|
||||
v[jj, i] = z * c - x * s;
|
||||
}
|
||||
z = pythag(f, h)
|
||||
w[j, 0] = z
|
||||
if (z != 0.0) {
|
||||
z = 1.0 / z
|
||||
c = f * z
|
||||
s = h * z
|
||||
}
|
||||
f = c * g + s * y
|
||||
x = c * y - s * g
|
||||
for (jj in 0 until m) {
|
||||
y = this[jj, j]
|
||||
z = this[jj, i]
|
||||
this[jj, j] = y * c + z * s
|
||||
this[jj, i] = z * c - y * s
|
||||
}
|
||||
}
|
||||
rv1[l] = 0.0
|
||||
rv1[k] = f
|
||||
w[k, 0] = x
|
||||
}
|
||||
}
|
||||
}
|
@ -2,14 +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.stability.nowarn=true
|
||||
|
||||
kotlin.jupyter.add.scanner=false
|
||||
kotlin.mpp.stability.nowarn=true
|
||||
kotlin.native.ignoreDisabledTargets=true
|
||||
#kotlin.incremental.js.ir=true
|
||||
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
|
||||
|
||||
toolsVersion=0.11.1-kotlin-1.6.10
|
||||
org.gradle.parallel=true
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -10,17 +10,17 @@ Extensions to MST API: transformations, dynamic compilation and visualization.
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-ast:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-ast:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-ast:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-ast:0.3.0")
|
||||
}
|
||||
```
|
||||
|
||||
@ -66,20 +66,19 @@ For example, the following code:
|
||||
|
||||
```kotlin
|
||||
import space.kscience.kmath.asm.compileToExpression
|
||||
import space.kscience.kmath.complex.ComplexField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
|
||||
"x+2".parseMath().compileToExpression(ComplexField)
|
||||
"x^3-x+3".parseMath().compileToExpression(DoubleField)
|
||||
```
|
||||
|
||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||
|
||||
```java
|
||||
import java.util.Map;
|
||||
import kotlin.jvm.functions.Function2;
|
||||
import space.kscience.kmath.asm.internal.MapIntrinsics;
|
||||
import space.kscience.kmath.complex.Complex;
|
||||
import space.kscience.kmath.expressions.Expression;
|
||||
import space.kscience.kmath.expressions.Symbol;
|
||||
import java.util.*;
|
||||
import kotlin.jvm.functions.*;
|
||||
import space.kscience.kmath.asm.internal.*;
|
||||
import space.kscience.kmath.complex.*;
|
||||
import space.kscience.kmath.expressions.*;
|
||||
|
||||
public final class CompiledExpression_45045_0 implements Expression<Complex> {
|
||||
private final Object[] constants;
|
||||
@ -91,6 +90,32 @@ public final class CompiledExpression_45045_0 implements Expression<Complex> {
|
||||
}
|
||||
```
|
||||
|
||||
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<Symbol, ? extends Double> arguments) {
|
||||
double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue();
|
||||
return Math.pow(var2, 3.0D) - var2 + 3.0D;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
#### Limitations
|
||||
@ -134,9 +159,9 @@ MstField { x + 2 }.compileToExpression(DoubleField)
|
||||
An example of emitted Wasm IR in the form of WAT:
|
||||
|
||||
```lisp
|
||||
(func $executable (param $0 f64) (result f64)
|
||||
(func \$executable (param \$0 f64) (result f64)
|
||||
(f64.add
|
||||
(local.get $0)
|
||||
(local.get \$0)
|
||||
(f64.const 2)
|
||||
)
|
||||
)
|
||||
|
32
kmath-commons/README.md
Normal file
32
kmath-commons/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-commons
|
||||
|
||||
Commons math binding for kmath
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-commons:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-commons:0.3.0")
|
||||
}
|
||||
```
|
@ -8,17 +8,17 @@ Complex and hypercomplex number systems in KMath.
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-complex:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-complex:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -29,6 +29,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-complex:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-complex:0.3.0")
|
||||
}
|
||||
```
|
||||
|
@ -15,17 +15,17 @@ performance calculations to code generation.
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-core:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-core:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -36,6 +36,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-core:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-core:0.3.0")
|
||||
}
|
||||
```
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this 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 abstract class Domain1D<T : Comparable<T>>(public val range: ClosedRange<T>) : Domain<T> {
|
||||
override val dimension: Int get() = 1
|
||||
|
||||
public operator fun contains(value: T): Boolean = range.contains(value)
|
||||
|
||||
override operator fun contains(point: Point<T>): Boolean {
|
||||
require(point.size == 0)
|
||||
return contains(point[0])
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableKMathAPI
|
||||
public class DoubleDomain1D(
|
||||
@Suppress("CanBeParameter") public val doubleRange: ClosedFloatingPointRange<Double>,
|
||||
) : Domain1D<Double>(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<Double>.center: Double
|
||||
get() = (range.endInclusive + range.start) / 2
|
@ -7,18 +7,28 @@ package space.kscience.kmath.domains
|
||||
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
|
||||
|
||||
/**
|
||||
*
|
||||
* HyperSquareDomain class.
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
* 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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public class HyperSquareDomain(private val lower: Buffer<Double>, private val upper: Buffer<Double>) : DoubleDomain {
|
||||
public class HyperSquareDomain(public val lower: Buffer<Double>, public val upper: Buffer<Double>) : 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."
|
||||
}
|
||||
}
|
||||
|
||||
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<Double>): Boolean = point.indices.all { i ->
|
||||
point[i] in lower[i]..upper[i]
|
||||
}
|
||||
|
@ -1,33 +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.domains
|
||||
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
|
||||
@UnstableKMathAPI
|
||||
public class UnivariateDomain(public val range: ClosedFloatingPointRange<Double>) : DoubleDomain {
|
||||
override val dimension: Int get() = 1
|
||||
|
||||
public operator fun contains(d: Double): Boolean = range.contains(d)
|
||||
|
||||
override operator fun contains(point: Point<Double>): Boolean {
|
||||
require(point.size == 0)
|
||||
return contains(point[0])
|
||||
}
|
||||
|
||||
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
|
||||
}
|
@ -3,43 +3,71 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
package space.kscience.kmath.misc
|
||||
|
||||
import kotlin.comparisons.*
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.VirtualBuffer
|
||||
|
||||
/**
|
||||
* Return a new list filled with buffer indices. Indice order is defined by sorting associated buffer value.
|
||||
* This feature allows to sort buffer values without reordering its content.
|
||||
* 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 List of buffer indices, sorted by associated value.
|
||||
* @return Buffer indices, sorted by associated value.
|
||||
*/
|
||||
@PerformancePitfall
|
||||
@UnstableKMathAPI
|
||||
public fun <V: Comparable<V>> Buffer<V>.permSort() : IntArray = _permSortWith(compareBy<Int> { get(it) })
|
||||
public fun <V : Comparable<V>> Buffer<V>.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 <V : Comparable<V>> Buffer<V>.sorted(): Buffer<V> {
|
||||
val permutations = indicesSorted()
|
||||
return VirtualBuffer(size) { this[permutations[it]] }
|
||||
}
|
||||
|
||||
@PerformancePitfall
|
||||
@UnstableKMathAPI
|
||||
public fun <V: Comparable<V>> Buffer<V>.permSortDescending() : IntArray = _permSortWith(compareByDescending<Int> { get(it) })
|
||||
public fun <V : Comparable<V>> Buffer<V>.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 <V : Comparable<V>> Buffer<V>.sortedDescending(): Buffer<V> {
|
||||
val permutations = indicesSortedDescending()
|
||||
return VirtualBuffer(size) { this[permutations[it]] }
|
||||
}
|
||||
|
||||
@PerformancePitfall
|
||||
@UnstableKMathAPI
|
||||
public fun <V, C: Comparable<C>> Buffer<V>.permSortBy(selector: (V) -> C) : IntArray = _permSortWith(compareBy<Int> { selector(get(it)) })
|
||||
public fun <V, C : Comparable<C>> Buffer<V>.indicesSortedBy(selector: (V) -> C): IntArray =
|
||||
permSortIndicesWith(compareBy { selector(get(it)) })
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public fun <V, C : Comparable<C>> Buffer<V>.sortedBy(selector: (V) -> C): Buffer<V> {
|
||||
val permutations = indicesSortedBy(selector)
|
||||
return VirtualBuffer(size) { this[permutations[it]] }
|
||||
}
|
||||
|
||||
@PerformancePitfall
|
||||
@UnstableKMathAPI
|
||||
public fun <V, C: Comparable<C>> Buffer<V>.permSortByDescending(selector: (V) -> C) : IntArray = _permSortWith(compareByDescending<Int> { selector(get(it)) })
|
||||
public fun <V, C : Comparable<C>> Buffer<V>.indicesSortedByDescending(selector: (V) -> C): IntArray =
|
||||
permSortIndicesWith(compareByDescending { selector(get(it)) })
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public fun <V, C : Comparable<C>> Buffer<V>.sortedByDescending(selector: (V) -> C): Buffer<V> {
|
||||
val permutations = indicesSortedByDescending(selector)
|
||||
return VirtualBuffer(size) { this[permutations[it]] }
|
||||
}
|
||||
|
||||
@PerformancePitfall
|
||||
@UnstableKMathAPI
|
||||
public fun <V> Buffer<V>.permSortWith(comparator : Comparator<V>) : IntArray = _permSortWith { i1, i2 -> comparator.compare(get(i1), get(i2)) }
|
||||
public fun <V> Buffer<V>.indicesSortedWith(comparator: Comparator<V>): IntArray =
|
||||
permSortIndicesWith { i1, i2 -> comparator.compare(get(i1), get(i2)) }
|
||||
|
||||
@PerformancePitfall
|
||||
@UnstableKMathAPI
|
||||
private fun <V> Buffer<V>._permSortWith(comparator : Comparator<Int>) : IntArray {
|
||||
if (size < 2) return IntArray(size)
|
||||
private fun <V> Buffer<V>.permSortIndicesWith(comparator: Comparator<Int>): IntArray {
|
||||
if (size < 2) return IntArray(size) { 0 }
|
||||
|
||||
/* TODO: optimisation : keep a constant big array of indices (Ex: from 0 to 4096), then create indice
|
||||
/* 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.
|
||||
@ -53,3 +81,12 @@ private fun <V> Buffer<V>._permSortWith(comparator : Comparator<Int>) : IntArray
|
||||
*/
|
||||
return packedIndices.sortedWith(comparator).toIntArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the [Buffer] is sorted (ascending) and throws [IllegalArgumentException] if it is not.
|
||||
*/
|
||||
public fun <T : Comparable<T>> Buffer<T>.requireSorted() {
|
||||
for (i in 0..(size - 2)) {
|
||||
require(get(i + 1) >= get(i)) { "The buffer is not sorted at index $i" }
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ public interface RingOpsND<T, out A : RingOps<T>> : RingOps<StructureND<T>>, Gro
|
||||
override fun multiply(left: StructureND<T>, right: StructureND<T>): StructureND<T> =
|
||||
zip(left, right) { aValue, bValue -> multiply(aValue, bValue) }
|
||||
|
||||
//TODO move to extensions after KEEP-176
|
||||
//TODO move to extensions with context receivers
|
||||
|
||||
/**
|
||||
* Multiplies an ND structure by an element of it.
|
||||
|
@ -32,18 +32,23 @@ public open class BufferND<out T>(
|
||||
/**
|
||||
* Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferND]
|
||||
*/
|
||||
public inline fun <T, reified R : Any> StructureND<T>.mapToBuffer(
|
||||
factory: BufferFactory<R> = Buffer.Companion::auto,
|
||||
public inline fun <T, R : Any> StructureND<T>.mapToBuffer(
|
||||
factory: BufferFactory<R>,
|
||||
crossinline transform: (T) -> R,
|
||||
): BufferND<R> {
|
||||
return if (this is BufferND<T>)
|
||||
BufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) })
|
||||
else {
|
||||
val strides = DefaultStrides(shape)
|
||||
BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
||||
}
|
||||
): BufferND<R> = if (this is BufferND<T>)
|
||||
BufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) })
|
||||
else {
|
||||
val strides = DefaultStrides(shape)
|
||||
BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform structure to a new structure using inferred [BufferFactory]
|
||||
*/
|
||||
public inline fun <T, reified R : Any> StructureND<T>.mapToBuffer(
|
||||
crossinline transform: (T) -> R,
|
||||
): BufferND<R> = mapToBuffer(Buffer.Companion::auto, transform)
|
||||
|
||||
/**
|
||||
* Represents [MutableStructureND] over [MutableBuffer].
|
||||
*
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
package space.kscience.kmath.operations
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferFactory
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
@ -53,7 +52,7 @@ public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
|
||||
*/
|
||||
private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapInline(
|
||||
buffer: Buffer<T>,
|
||||
crossinline block: A.(T) -> T
|
||||
crossinline block: A.(T) -> T,
|
||||
): Buffer<T> = bufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) }
|
||||
|
||||
/**
|
||||
@ -61,7 +60,7 @@ private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapInline(
|
||||
*/
|
||||
private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapIndexedInline(
|
||||
buffer: Buffer<T>,
|
||||
crossinline block: A.(index: Int, arg: T) -> T
|
||||
crossinline block: A.(index: Int, arg: T) -> T,
|
||||
): Buffer<T> = bufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) }
|
||||
|
||||
/**
|
||||
@ -70,7 +69,7 @@ private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.mapIndexedInline(
|
||||
private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.zipInline(
|
||||
l: Buffer<T>,
|
||||
r: Buffer<T>,
|
||||
crossinline block: A.(l: T, r: T) -> T
|
||||
crossinline block: A.(l: T, r: T) -> T,
|
||||
): Buffer<T> {
|
||||
require(l.size == r.size) { "Incompatible buffer sizes. left: ${l.size}, right: ${r.size}" }
|
||||
return bufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) }
|
||||
@ -127,13 +126,13 @@ public fun <T, A : ExponentialOperations<T>> BufferAlgebra<T, A>.atanh(arg: Buff
|
||||
mapInline(arg) { atanh(it) }
|
||||
|
||||
public fun <T, A : PowerOperations<T>> BufferAlgebra<T, A>.pow(arg: Buffer<T>, pow: Number): Buffer<T> =
|
||||
mapInline(arg) {it.pow(pow) }
|
||||
mapInline(arg) { it.pow(pow) }
|
||||
|
||||
|
||||
public open class BufferRingOps<T, A: Ring<T>>(
|
||||
public open class BufferRingOps<T, A : Ring<T>>(
|
||||
override val elementAlgebra: A,
|
||||
override val bufferFactory: BufferFactory<T>,
|
||||
) : BufferAlgebra<T, A>, RingOps<Buffer<T>>{
|
||||
) : BufferAlgebra<T, A>, RingOps<Buffer<T>> {
|
||||
|
||||
override fun add(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l + r }
|
||||
override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l * r }
|
||||
@ -152,10 +151,11 @@ public val ShortRing.bufferAlgebra: BufferRingOps<Short, ShortRing>
|
||||
public open class BufferFieldOps<T, A : Field<T>>(
|
||||
elementAlgebra: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferRingOps<T, A>(elementAlgebra, bufferFactory), BufferAlgebra<T, A>, FieldOps<Buffer<T>>, ScaleOperations<Buffer<T>> {
|
||||
) : BufferRingOps<T, A>(elementAlgebra, bufferFactory), BufferAlgebra<T, A>, FieldOps<Buffer<T>>,
|
||||
ScaleOperations<Buffer<T>> {
|
||||
|
||||
override fun add(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l + r }
|
||||
override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l * r }
|
||||
// override fun add(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l + r }
|
||||
// override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l * r }
|
||||
override fun divide(left: Buffer<T>, right: Buffer<T>): Buffer<T> = zipInline(left, right) { l, r -> l / r }
|
||||
|
||||
override fun scale(a: Buffer<T>, value: Double): Buffer<T> = a.map { scale(it, value) }
|
||||
@ -168,7 +168,7 @@ public open class BufferFieldOps<T, A : Field<T>>(
|
||||
public class BufferField<T, A : Field<T>>(
|
||||
elementAlgebra: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
override val size: Int
|
||||
override val size: Int,
|
||||
) : BufferFieldOps<T, A>(elementAlgebra, bufferFactory), Field<Buffer<T>>, WithSize {
|
||||
|
||||
override val zero: Buffer<T> = bufferFactory(size) { elementAlgebra.zero }
|
||||
|
@ -105,6 +105,16 @@ public interface Buffer<out T> {
|
||||
*/
|
||||
public val Buffer<*>.indices: IntRange get() = 0 until size
|
||||
|
||||
public fun <T> Buffer<T>.first(): T {
|
||||
require(size > 0) { "Can't get the first element of empty buffer" }
|
||||
return get(0)
|
||||
}
|
||||
|
||||
public fun <T> Buffer<T>.last(): T {
|
||||
require(size > 0) { "Can't get the last element of empty buffer" }
|
||||
return get(size - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Immutable wrapper for [MutableBuffer].
|
||||
*
|
||||
|
@ -6,14 +6,13 @@
|
||||
package space.kscience.kmath.misc
|
||||
|
||||
import space.kscience.kmath.misc.PermSortTest.Platform.*
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
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
|
||||
|
||||
class PermSortTest {
|
||||
|
||||
@ -29,9 +28,9 @@ class PermSortTest {
|
||||
@Test
|
||||
fun testOnEmptyBuffer() {
|
||||
val emptyBuffer = IntBuffer(0) {it}
|
||||
var permutations = emptyBuffer.permSort()
|
||||
var permutations = emptyBuffer.indicesSorted()
|
||||
assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result")
|
||||
permutations = emptyBuffer.permSortDescending()
|
||||
permutations = emptyBuffer.indicesSortedDescending()
|
||||
assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result")
|
||||
}
|
||||
|
||||
@ -47,25 +46,25 @@ class PermSortTest {
|
||||
|
||||
@Test
|
||||
fun testPermSortBy() {
|
||||
val permutations = platforms.permSortBy { it.name }
|
||||
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.permSortByDescending { it.name }
|
||||
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.permSortWith { p1, p2 -> p1.name.length.compareTo(p2.name.length) }
|
||||
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.permSortWith(compareByDescending { it.name.length })
|
||||
permutations = platforms.indicesSortedWith(compareByDescending { it.name.length })
|
||||
assertContentEquals(expected.reversed(), permutations.map { platforms[it] }, "PermSort using custom descending comparator")
|
||||
}
|
||||
|
||||
@ -75,7 +74,7 @@ class PermSortTest {
|
||||
println("Test randomization seed: $seed")
|
||||
|
||||
val buffer = Random(seed).buffer(bufferSize)
|
||||
val indices = buffer.permSort()
|
||||
val indices = buffer.indicesSorted()
|
||||
|
||||
assertEquals(bufferSize, indices.size)
|
||||
// Ensure no doublon is present in indices
|
||||
@ -87,7 +86,7 @@ class PermSortTest {
|
||||
assertTrue(current <= next, "Permutation indices not properly sorted")
|
||||
}
|
||||
|
||||
val descIndices = buffer.permSortDescending()
|
||||
val descIndices = buffer.indicesSortedDescending()
|
||||
assertEquals(bufferSize, descIndices.size)
|
||||
// Ensure no doublon is present in indices
|
||||
assertEquals(descIndices.toSet().size, descIndices.size)
|
||||
|
32
kmath-coroutines/README.md
Normal file
32
kmath-coroutines/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-coroutines
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-coroutines:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-coroutines:0.3.0")
|
||||
}
|
||||
```
|
32
kmath-dimensions/README.md
Normal file
32
kmath-dimensions/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# 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.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-dimensions:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-dimensions:0.3.0")
|
||||
}
|
||||
```
|
@ -9,17 +9,17 @@ EJML based linear algebra implementation.
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-ejml:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-ejml:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -30,6 +30,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-ejml:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-ejml:0.3.0")
|
||||
}
|
||||
```
|
||||
|
@ -9,17 +9,17 @@ Specialization of KMath APIs for Double numbers.
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-for-real:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-for-real:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -30,6 +30,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-for-real:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-for-real:0.3.0")
|
||||
}
|
||||
```
|
||||
|
@ -21,19 +21,22 @@ readme {
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
@ -11,17 +11,17 @@ Functions and interpolations.
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-functions:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-functions:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -32,6 +32,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-functions:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-functions:0.3.0")
|
||||
}
|
||||
```
|
||||
|
@ -7,6 +7,6 @@ package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
|
||||
public typealias UnivariateFunction<T> = (T) -> T
|
||||
public typealias Function1D<T> = (T) -> T
|
||||
|
||||
public typealias MultivariateFunction<T> = (Buffer<T>) -> T
|
||||
public typealias FunctionND<T> = (Buffer<T>) -> T
|
@ -28,6 +28,8 @@ public fun <T : Comparable<T>> PiecewisePolynomial<T>.integrate(algebra: Field<T
|
||||
/**
|
||||
* 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 <T : Comparable<T>> PiecewisePolynomial<T>.integrate(
|
||||
@ -98,6 +100,7 @@ public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@UnstableKMathAPI
|
||||
public inline val DoubleField.splineIntegrator: UnivariateIntegrator<Double>
|
||||
get() = DoubleSplineIntegrator
|
@ -9,6 +9,7 @@ package space.kscience.kmath.interpolation
|
||||
|
||||
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
|
||||
@ -59,3 +60,33 @@ public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
|
||||
val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer())
|
||||
return interpolatePolynomials(pointSet)
|
||||
}
|
||||
|
||||
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
|
||||
x: Buffer<T>,
|
||||
y: Buffer<T>,
|
||||
): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra)
|
||||
|
||||
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
|
||||
data: Map<T, T>,
|
||||
): (T) -> T? = interpolatePolynomials(data).asFunction(algebra)
|
||||
|
||||
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
|
||||
data: List<Pair<T, T>>,
|
||||
): (T) -> T? = interpolatePolynomials(data).asFunction(algebra)
|
||||
|
||||
|
||||
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
|
||||
x: Buffer<T>,
|
||||
y: Buffer<T>,
|
||||
defaultValue: T,
|
||||
): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue)
|
||||
|
||||
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
|
||||
data: Map<T, T>,
|
||||
defaultValue: T,
|
||||
): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue)
|
||||
|
||||
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
|
||||
data: List<Pair<T, T>>,
|
||||
defaultValue: T,
|
||||
): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue)
|
@ -22,6 +22,7 @@ internal fun <T : Comparable<T>> 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<T : Comparable<T>>(override val algebra: Field<T>) : PolynomialInterpolator<T> {
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
override fun interpolatePolynomials(points: XYColumnarData<T, T, T>): PiecewisePolynomial<T> = algebra {
|
||||
require(points.size > 0) { "Point array should not be empty" }
|
||||
@ -37,3 +38,6 @@ public class LinearInterpolator<T : Comparable<T>>(override val algebra: Field<T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public val <T : Comparable<T>> Field<T>.linearInterpolator: LinearInterpolator<T>
|
||||
get() = LinearInterpolator(this)
|
||||
|
@ -63,8 +63,8 @@ public class SplineInterpolator<T : Comparable<T>>(
|
||||
//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,
|
||||
b - 2 * c * x0 + 3 * d * x02,
|
||||
c - 3 * d * x0,
|
||||
d
|
||||
)
|
||||
cOld = c
|
||||
@ -72,8 +72,12 @@ public class SplineInterpolator<T : Comparable<T>>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public companion object {
|
||||
public val double: SplineInterpolator<Double> = SplineInterpolator(DoubleField, ::DoubleBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public fun <T : Comparable<T>> Field<T>.splineInterpolator(
|
||||
bufferFactory: MutableBufferFactory<T>,
|
||||
): SplineInterpolator<T> = SplineInterpolator(this, bufferFactory)
|
||||
|
||||
public val DoubleField.splineInterpolator: SplineInterpolator<Double>
|
||||
get() = SplineInterpolator(this, ::DoubleBuffer)
|
@ -5,8 +5,6 @@
|
||||
|
||||
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
|
||||
@ -21,8 +19,8 @@ internal class LinearInterpolatorTest {
|
||||
3.0 to 4.0
|
||||
)
|
||||
|
||||
val polynomial: PiecewisePolynomial<Double> = LinearInterpolator(DoubleField).interpolatePolynomials(data)
|
||||
val function = polynomial.asFunction(DoubleField)
|
||||
//val polynomial: PiecewisePolynomial<Double> = DoubleField.linearInterpolator.interpolatePolynomials(data)
|
||||
val function = DoubleField.linearInterpolator.interpolate(data)
|
||||
assertEquals(null, function(-1.0))
|
||||
assertEquals(0.5, function(0.5))
|
||||
assertEquals(2.0, function(1.5))
|
||||
|
@ -5,8 +5,6 @@
|
||||
|
||||
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.math.PI
|
||||
import kotlin.math.sin
|
||||
@ -21,9 +19,10 @@ internal class SplineInterpolatorTest {
|
||||
x to sin(x)
|
||||
}
|
||||
|
||||
val polynomial: PiecewisePolynomial<Double> = SplineInterpolator.double.interpolatePolynomials(data)
|
||||
//val polynomial: PiecewisePolynomial<Double> = DoubleField.splineInterpolator.interpolatePolynomials(data)
|
||||
|
||||
val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN)
|
||||
|
||||
val function = polynomial.asFunction(DoubleField, 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)
|
||||
|
32
kmath-geometry/README.md
Normal file
32
kmath-geometry/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-geometry
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-geometry:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-geometry:0.3.0")
|
||||
}
|
||||
```
|
32
kmath-histograms/README.md
Normal file
32
kmath-histograms/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-histograms
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-histograms:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-histograms:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-histograms:0.3.0")
|
||||
}
|
||||
```
|
@ -17,6 +17,8 @@ kotlin.sourceSets {
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation(project(":kmath-for-real"))
|
||||
implementation(projects.kmath.kmathStat)
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,8 @@ public interface Counter<T : Any> {
|
||||
public val value: T
|
||||
|
||||
public companion object {
|
||||
public fun double(): ObjectCounter<Double> = ObjectCounter(DoubleField)
|
||||
public fun ofDouble(): ObjectCounter<Double> = ObjectCounter(DoubleField)
|
||||
public fun <T: Any> of(group: Group<T>): ObjectCounter<T> = ObjectCounter(group)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,130 +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.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.operations.DoubleField
|
||||
import space.kscience.kmath.structures.*
|
||||
import kotlin.math.floor
|
||||
|
||||
public class DoubleHistogramSpace(
|
||||
private val lower: Buffer<Double>,
|
||||
private val upper: Buffer<Double>,
|
||||
private val binNums: IntArray = IntArray(lower.size) { 20 },
|
||||
) : IndexedHistogramSpace<Double, Double> {
|
||||
|
||||
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: IntArray = IntArray(binNums.size) { binNums[it] + 2 }
|
||||
override val histogramValueSpace: DoubleFieldND = DoubleField.ndAlgebra(*shape)
|
||||
|
||||
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<Double>): IntArray = IntArray(dimension) {
|
||||
getIndex(it, point[it])
|
||||
}
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
override fun getDomain(index: IntArray): Domain<Double> {
|
||||
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: Double): Bin<Double> {
|
||||
val domain = getDomain(index)
|
||||
return DomainBin(domain, value)
|
||||
}
|
||||
|
||||
override fun produce(builder: HistogramBuilder<Double>.() -> Unit): IndexedHistogram<Double, Double> {
|
||||
val ndCounter = StructureND.auto(shape) { Counter.double() }
|
||||
val hBuilder = HistogramBuilder<Double> { point, value ->
|
||||
val index = getIndex(point)
|
||||
ndCounter[index].add(value.toDouble())
|
||||
}
|
||||
hBuilder.apply(builder)
|
||||
val values: BufferND<Double> = ndCounter.mapToBuffer { it.value }
|
||||
return IndexedHistogram(this, values)
|
||||
}
|
||||
|
||||
override fun IndexedHistogram<Double, Double>.unaryMinus(): IndexedHistogram<Double, Double> = this * (-1)
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* Use it like
|
||||
* ```
|
||||
*FastHistogram.fromRanges(
|
||||
* (-1.0..1.0),
|
||||
* (-1.0..1.0)
|
||||
*)
|
||||
*```
|
||||
*/
|
||||
public fun fromRanges(vararg ranges: ClosedFloatingPointRange<Double>): DoubleHistogramSpace = DoubleHistogramSpace(
|
||||
ranges.map(ClosedFloatingPointRange<Double>::start).asBuffer(),
|
||||
ranges.map(ClosedFloatingPointRange<Double>::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<ClosedFloatingPointRange<Double>, Int>): DoubleHistogramSpace =
|
||||
DoubleHistogramSpace(
|
||||
ListBuffer(
|
||||
ranges
|
||||
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
|
||||
.map(ClosedFloatingPointRange<Double>::start)
|
||||
),
|
||||
|
||||
ListBuffer(
|
||||
ranges
|
||||
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
|
||||
.map(ClosedFloatingPointRange<Double>::endInclusive)
|
||||
),
|
||||
|
||||
ranges.map(Pair<ClosedFloatingPointRange<Double>, Int>::second).toIntArray()
|
||||
)
|
||||
}
|
||||
}
|
@ -13,14 +13,23 @@ import space.kscience.kmath.structures.asBuffer
|
||||
/**
|
||||
* The binned data element. Could be a histogram bin with a number of counts or an artificial construct.
|
||||
*/
|
||||
public interface Bin<in T : Any> : Domain<T> {
|
||||
public interface Bin<in T : Any, out V> : Domain<T> {
|
||||
/**
|
||||
* The value of this bin.
|
||||
*/
|
||||
public val value: Number
|
||||
public val binValue: V
|
||||
}
|
||||
|
||||
public interface Histogram<in T : Any, out B : Bin<T>> {
|
||||
/**
|
||||
* A simple histogram bin based on domain
|
||||
*/
|
||||
public data class DomainBin<in T : Comparable<T>, D : Domain<T>, out V>(
|
||||
public val domain: D,
|
||||
override val binValue: V,
|
||||
) : Bin<T, V>, Domain<T> by domain
|
||||
|
||||
|
||||
public interface Histogram<in T : Any, out V, out B : Bin<T, V>> {
|
||||
/**
|
||||
* Find existing bin, corresponding to given coordinates
|
||||
*/
|
||||
@ -32,29 +41,38 @@ public interface Histogram<in T : Any, out B : Bin<T>> {
|
||||
public val dimension: Int
|
||||
|
||||
public val bins: Iterable<B>
|
||||
|
||||
public companion object {
|
||||
//A discoverability root
|
||||
}
|
||||
}
|
||||
|
||||
public fun interface HistogramBuilder<in T : Any> {
|
||||
public interface HistogramBuilder<in T : Any, V : Any> {
|
||||
|
||||
/**
|
||||
* Increment appropriate bin
|
||||
* The default value increment for a bin
|
||||
*/
|
||||
public fun putValue(point: Point<out T>, value: Number)
|
||||
public val defaultValue: V
|
||||
|
||||
/**
|
||||
* Increment appropriate bin with given value
|
||||
*/
|
||||
public fun putValue(point: Point<out T>, value: V = defaultValue)
|
||||
|
||||
}
|
||||
|
||||
public fun <T : Any, B : Bin<T>> HistogramBuilder<T>.put(point: Point<out T>): Unit = putValue(point, 1.0)
|
||||
public fun <T : Any> HistogramBuilder<T, *>.put(point: Point<out T>): Unit = putValue(point)
|
||||
|
||||
public fun <T : Any> HistogramBuilder<T>.put(vararg point: T): Unit = put(point.asBuffer())
|
||||
public fun <T : Any> HistogramBuilder<T, *>.put(vararg point: T): Unit = put(point.asBuffer())
|
||||
|
||||
public fun HistogramBuilder<Double>.put(vararg point: Number): Unit =
|
||||
public fun HistogramBuilder<Double, *>.put(vararg point: Number): Unit =
|
||||
put(DoubleBuffer(point.map { it.toDouble() }.toDoubleArray()))
|
||||
|
||||
public fun HistogramBuilder<Double>.put(vararg point: Double): Unit = put(DoubleBuffer(point))
|
||||
public fun <T : Any> HistogramBuilder<T>.fill(sequence: Iterable<Point<T>>): Unit = sequence.forEach { put(it) }
|
||||
public fun HistogramBuilder<Double, *>.put(vararg point: Double): Unit = put(DoubleBuffer(point))
|
||||
public fun <T : Any> HistogramBuilder<T, *>.fill(sequence: Iterable<Point<T>>): Unit = sequence.forEach { put(it) }
|
||||
|
||||
/**
|
||||
* Pass a sequence builder into histogram
|
||||
*/
|
||||
public fun <T : Any> HistogramBuilder<T>.fill(block: suspend SequenceScope<Point<T>>.() -> Unit): Unit =
|
||||
public fun <T : Any> HistogramBuilder<T, *>.fill(block: suspend SequenceScope<Point<T>>.() -> Unit): Unit =
|
||||
fill(sequence(block).asIterable())
|
||||
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this 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.Domain1D
|
||||
import space.kscience.kmath.domains.center
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
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<T : Comparable<T>, out V>(
|
||||
public val domain: Domain1D<T>,
|
||||
override val binValue: V,
|
||||
) : Bin<T, V>, ClosedRange<T> by domain.range {
|
||||
|
||||
override val dimension: Int get() = 1
|
||||
|
||||
override fun contains(point: Buffer<T>): Boolean = point.size == 1 && contains(point[0])
|
||||
}
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public interface Histogram1D<T : Comparable<T>, V> : Histogram<T, V, Bin1D<T, V>> {
|
||||
override val dimension: Int get() = 1
|
||||
public operator fun get(value: T): Bin1D<T, V>?
|
||||
override operator fun get(point: Buffer<T>): Bin1D<T, V>? = get(point[0])
|
||||
}
|
||||
|
||||
public interface Histogram1DBuilder<in T : Any, V : Any> : HistogramBuilder<T, V> {
|
||||
/**
|
||||
* Thread safe put operation
|
||||
*/
|
||||
public fun putValue(at: T, value: V = defaultValue)
|
||||
|
||||
override fun putValue(point: Point<out T>, value: V) {
|
||||
require(point.size == 1) { "Only points with single value could be used in Histogram1D" }
|
||||
putValue(point[0], value)
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun Histogram1DBuilder<Double, *>.fill(items: Iterable<Double>): Unit =
|
||||
items.forEach(this::putValue)
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun Histogram1DBuilder<Double, *>.fill(array: DoubleArray): Unit =
|
||||
array.forEach(this::putValue)
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun <T : Any> Histogram1DBuilder<T, *>.fill(buffer: Buffer<T>): Unit =
|
||||
buffer.asSequence().forEach(this::putValue)
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public val Bin1D<Double, *>.center: Double get() = domain.center
|
@ -0,0 +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.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.histogram
|
||||
|
||||
import space.kscience.kmath.domains.Domain
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.nd.DefaultStrides
|
||||
import space.kscience.kmath.nd.FieldOpsND
|
||||
import space.kscience.kmath.nd.Shape
|
||||
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<T : Comparable<T>, D : Domain<T>, V : Any>(
|
||||
public val group: HistogramGroupND<T, D, V>,
|
||||
internal val values: StructureND<V>,
|
||||
) : Histogram<T, V, DomainBin<T, D, V>> {
|
||||
|
||||
override fun get(point: Point<T>): DomainBin<T, D, V>? {
|
||||
val index = group.getIndexOrNull(point) ?: return null
|
||||
return group.produceBin(index, values[index])
|
||||
}
|
||||
|
||||
override val dimension: Int get() = group.shape.size
|
||||
|
||||
override val bins: Iterable<DomainBin<T, D, V>>
|
||||
get() = DefaultStrides(group.shape).asSequence().map {
|
||||
group.produceBin(it, values[it])
|
||||
}.asIterable()
|
||||
}
|
||||
|
||||
/**
|
||||
* A space for producing histograms with values in a NDStructure
|
||||
*/
|
||||
public interface HistogramGroupND<T : Comparable<T>, D : Domain<T>, V : Any> :
|
||||
Group<HistogramND<T, D, V>>, ScaleOperations<HistogramND<T, D, V>> {
|
||||
public val shape: Shape
|
||||
public val valueAlgebraND: FieldOpsND<V, *> //= 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<T>): IntArray?
|
||||
|
||||
/**
|
||||
* Get a bin domain represented by given index
|
||||
*/
|
||||
public fun getDomain(index: IntArray): Domain<T>?
|
||||
|
||||
public fun produceBin(index: IntArray, value: V): DomainBin<T, D, V>
|
||||
|
||||
public fun produce(builder: HistogramBuilder<T, V>.() -> Unit): HistogramND<T, D, V>
|
||||
|
||||
override fun add(left: HistogramND<T, D, V>, right: HistogramND<T, D, V>): HistogramND<T, D, V> {
|
||||
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<T, D, V>, value: Double): HistogramND<T, D, V> {
|
||||
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<T, D, V> get() = produce { }
|
||||
}
|
||||
|
@ -1,82 +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.histogram
|
||||
|
||||
import space.kscience.kmath.domains.Domain
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.DefaultStrides
|
||||
import space.kscience.kmath.nd.FieldND
|
||||
import space.kscience.kmath.nd.Shape
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.operations.Group
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import space.kscience.kmath.operations.invoke
|
||||
|
||||
/**
|
||||
* A simple histogram bin based on domain
|
||||
*/
|
||||
public data class DomainBin<in T : Comparable<T>>(
|
||||
public val domain: Domain<T>,
|
||||
override val value: Number,
|
||||
) : Bin<T>, Domain<T> by domain
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class IndexedHistogram<T : Comparable<T>, V : Any>(
|
||||
public val context: IndexedHistogramSpace<T, V>,
|
||||
public val values: StructureND<V>,
|
||||
) : Histogram<T, Bin<T>> {
|
||||
|
||||
override fun get(point: Point<T>): Bin<T>? {
|
||||
val index = context.getIndex(point) ?: return null
|
||||
return context.produceBin(index, values[index])
|
||||
}
|
||||
|
||||
override val dimension: Int get() = context.shape.size
|
||||
|
||||
override val bins: Iterable<Bin<T>>
|
||||
get() = DefaultStrides(context.shape).asSequence().map {
|
||||
context.produceBin(it, values[it])
|
||||
}.asIterable()
|
||||
}
|
||||
|
||||
/**
|
||||
* A space for producing histograms with values in a NDStructure
|
||||
*/
|
||||
public interface IndexedHistogramSpace<T : Comparable<T>, V : Any>
|
||||
: Group<IndexedHistogram<T, V>>, ScaleOperations<IndexedHistogram<T, V>> {
|
||||
//public val valueSpace: Space<V>
|
||||
public val shape: Shape
|
||||
public val histogramValueSpace: FieldND<V, *> //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape),
|
||||
|
||||
/**
|
||||
* Resolve index of the bin including given [point]
|
||||
*/
|
||||
public fun getIndex(point: Point<T>): IntArray?
|
||||
|
||||
/**
|
||||
* Get a bin domain represented by given index
|
||||
*/
|
||||
public fun getDomain(index: IntArray): Domain<T>?
|
||||
|
||||
public fun produceBin(index: IntArray, value: V): Bin<T>
|
||||
|
||||
public fun produce(builder: HistogramBuilder<T>.() -> Unit): IndexedHistogram<T, V>
|
||||
|
||||
override fun add(left: IndexedHistogram<T, V>, right: IndexedHistogram<T, V>): IndexedHistogram<T, V> {
|
||||
require(left.context == this) { "Can't operate on a histogram produced by external space" }
|
||||
require(right.context == this) { "Can't operate on a histogram produced by external space" }
|
||||
return IndexedHistogram(this, histogramValueSpace { left.values + right.values })
|
||||
}
|
||||
|
||||
override fun scale(a: IndexedHistogram<T, V>, value: Double): IndexedHistogram<T, V> {
|
||||
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<T, V> get() = produce { }
|
||||
}
|
||||
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this 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.DoubleDomain1D
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
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<V : Any>(
|
||||
public val group: UniformHistogram1DGroup<V, *>,
|
||||
internal val values: Map<Int, V>,
|
||||
) : Histogram1D<Double, V> {
|
||||
|
||||
private val startPoint get() = group.startPoint
|
||||
private val binSize get() = group.binSize
|
||||
|
||||
private fun produceBin(index: Int, value: V): Bin1D<Double, V> {
|
||||
val domain = DoubleDomain1D((startPoint + index * binSize)..(startPoint + (index + 1) * binSize))
|
||||
return Bin1D(domain, value)
|
||||
}
|
||||
|
||||
override val bins: Iterable<Bin1D<Double, V>> get() = values.map { produceBin(it.key, it.value) }
|
||||
|
||||
override fun get(value: Double): Bin1D<Double, V>? {
|
||||
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<V : Any, A>(
|
||||
public val valueAlgebra: A,
|
||||
public val binSize: Double,
|
||||
public val startPoint: Double = 0.0,
|
||||
) : Group<Histogram1D<Double, V>>, ScaleOperations<Histogram1D<Double, V>> where A : Ring<V>, A : ScaleOperations<V> {
|
||||
|
||||
override val zero: UniformHistogram1D<V> = 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<Double, V>,
|
||||
right: Histogram1D<Double, V>,
|
||||
): UniformHistogram1D<V> = 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<Double, V>.unaryMinus(): UniformHistogram1D<V> = valueAlgebra {
|
||||
UniformHistogram1D(this@UniformHistogram1DGroup, produceFrom(this@unaryMinus).values.mapValues { -it.value })
|
||||
}
|
||||
|
||||
override fun scale(
|
||||
a: Histogram1D<Double, V>,
|
||||
value: Double,
|
||||
): UniformHistogram1D<V> = UniformHistogram1D(
|
||||
this@UniformHistogram1DGroup,
|
||||
produceFrom(a).values.mapValues { valueAlgebra.scale(it.value, value) }
|
||||
)
|
||||
|
||||
/**
|
||||
* Fill histogram.
|
||||
*/
|
||||
public inline fun produce(block: Histogram1DBuilder<Double, V>.() -> Unit): UniformHistogram1D<V> {
|
||||
val map = HashMap<Int, V>()
|
||||
val builder = object : Histogram1DBuilder<Double, V> {
|
||||
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<Double, V>,
|
||||
): UniformHistogram1D<V> = if ((histogram as? UniformHistogram1D)?.group == this) {
|
||||
histogram
|
||||
} else {
|
||||
val map = HashMap<Int, V>()
|
||||
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 <V : Any, A> Histogram.Companion.uniform1D(
|
||||
valueAlgebra: A,
|
||||
binSize: Double,
|
||||
startPoint: Double = 0.0,
|
||||
): UniformHistogram1DGroup<V, A> where A : Ring<V>, A : ScaleOperations<V> =
|
||||
UniformHistogram1DGroup(valueAlgebra, binSize, startPoint)
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun <V : Any> UniformHistogram1DGroup<V, *>.produce(
|
||||
buffer: Buffer<Double>,
|
||||
): UniformHistogram1D<V> = produce { fill(buffer) }
|
||||
|
||||
/**
|
||||
* Map of bin centers to bin values
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public val <V : Any> UniformHistogram1D<V>.binValues: Map<Double, V>
|
||||
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 <V : Any> UniformHistogram1D<V>.binValuesNormalized: Map<Double, V>
|
||||
// get() = group.valueAlgebra {
|
||||
// bins.associate { it.center to it.binValue / group.binSize }
|
||||
// }
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath 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.domains.HyperSquareDomain
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.*
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.Field
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.structures.*
|
||||
import kotlin.math.floor
|
||||
|
||||
public typealias HyperSquareBin<V> = DomainBin<Double, HyperSquareDomain, V>
|
||||
|
||||
/**
|
||||
* Multivariate histogram space for hyper-square real-field bins.
|
||||
* @param bufferFactory is an optional parameter used to optimize buffer production.
|
||||
*/
|
||||
public class UniformHistogramGroupND<V : Any, A : Field<V>>(
|
||||
override val valueAlgebraND: FieldOpsND<V, A>,
|
||||
private val lower: Buffer<Double>,
|
||||
private val upper: Buffer<Double>,
|
||||
private val binNums: IntArray = IntArray(lower.size) { 20 },
|
||||
private val bufferFactory: BufferFactory<V> = Buffer.Companion::boxing,
|
||||
) : HistogramGroupND<Double, HyperSquareDomain, V> {
|
||||
|
||||
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: IntArray = 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<Double>): 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<V> {
|
||||
val domain = getDomain(index)
|
||||
return DomainBin(domain, value)
|
||||
}
|
||||
|
||||
|
||||
override fun produce(builder: HistogramBuilder<Double, V>.() -> Unit): HistogramND<Double, HyperSquareDomain, V> {
|
||||
val ndCounter = StructureND.buffered(shape) { Counter.of(valueAlgebraND.elementAlgebra) }
|
||||
val hBuilder = object : HistogramBuilder<Double, V> {
|
||||
override val defaultValue: V get() = valueAlgebraND.elementAlgebra.one
|
||||
|
||||
override fun putValue(point: Point<out Double>, value: V) = with(valueAlgebraND.elementAlgebra) {
|
||||
val index = getIndexOrNull(point)
|
||||
ndCounter[index].add(value)
|
||||
}
|
||||
}
|
||||
hBuilder.apply(builder)
|
||||
val values: BufferND<V> = ndCounter.mapToBuffer(bufferFactory) { it.value }
|
||||
return HistogramND(this, values)
|
||||
}
|
||||
|
||||
override fun HistogramND<Double, HyperSquareDomain, V>.unaryMinus(): HistogramND<Double, HyperSquareDomain, V> =
|
||||
this * (-1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use it like
|
||||
* ```
|
||||
*FastHistogram.fromRanges(
|
||||
* (-1.0..1.0),
|
||||
* (-1.0..1.0)
|
||||
*)
|
||||
*```
|
||||
*/
|
||||
public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
|
||||
valueAlgebraND: FieldOpsND<V, A>,
|
||||
vararg ranges: ClosedFloatingPointRange<Double>,
|
||||
bufferFactory: BufferFactory<V> = Buffer.Companion::boxing,
|
||||
): UniformHistogramGroupND<V, A> = UniformHistogramGroupND(
|
||||
valueAlgebraND,
|
||||
ranges.map(ClosedFloatingPointRange<Double>::start).asBuffer(),
|
||||
ranges.map(ClosedFloatingPointRange<Double>::endInclusive).asBuffer(),
|
||||
bufferFactory = bufferFactory
|
||||
)
|
||||
|
||||
public fun Histogram.Companion.uniformDoubleNDFromRanges(
|
||||
vararg ranges: ClosedFloatingPointRange<Double>,
|
||||
): UniformHistogramGroupND<Double, DoubleField> =
|
||||
uniformNDFromRanges(DoubleFieldOpsND, *ranges, bufferFactory = ::DoubleBuffer)
|
||||
|
||||
|
||||
/**
|
||||
* Use it like
|
||||
* ```
|
||||
*FastHistogram.fromRanges(
|
||||
* (-1.0..1.0) to 50,
|
||||
* (-1.0..1.0) to 32
|
||||
*)
|
||||
*```
|
||||
*/
|
||||
public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
|
||||
valueAlgebraND: FieldOpsND<V, A>,
|
||||
vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>,
|
||||
bufferFactory: BufferFactory<V> = Buffer.Companion::boxing,
|
||||
): UniformHistogramGroupND<V, A> = UniformHistogramGroupND(
|
||||
valueAlgebraND,
|
||||
ListBuffer(
|
||||
ranges
|
||||
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
|
||||
.map(ClosedFloatingPointRange<Double>::start)
|
||||
),
|
||||
ListBuffer(
|
||||
ranges
|
||||
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
|
||||
.map(ClosedFloatingPointRange<Double>::endInclusive)
|
||||
),
|
||||
ranges.map(Pair<ClosedFloatingPointRange<Double>, Int>::second).toIntArray(),
|
||||
bufferFactory = bufferFactory
|
||||
)
|
||||
|
||||
public fun Histogram.Companion.uniformDoubleNDFromRanges(
|
||||
vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>,
|
||||
): UniformHistogramGroupND<Double, DoubleField> =
|
||||
uniformNDFromRanges(DoubleFieldOpsND, *ranges, bufferFactory = ::DoubleBuffer)
|
@ -3,8 +3,11 @@
|
||||
* 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.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.DefaultStrides
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.real.DoubleVector
|
||||
@ -14,14 +17,14 @@ import kotlin.test.*
|
||||
internal class MultivariateHistogramTest {
|
||||
@Test
|
||||
fun testSinglePutHistogram() {
|
||||
val hSpace = DoubleHistogramSpace.fromRanges(
|
||||
val hSpace = Histogram.uniformDoubleNDFromRanges(
|
||||
(-1.0..1.0),
|
||||
(-1.0..1.0)
|
||||
)
|
||||
val histogram = hSpace.produce {
|
||||
put(0.55, 0.55)
|
||||
}
|
||||
val bin = histogram.bins.find { it.value.toInt() > 0 } ?: fail()
|
||||
val bin = histogram.bins.find { it.binValue.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)) }
|
||||
@ -29,7 +32,7 @@ internal class MultivariateHistogramTest {
|
||||
|
||||
@Test
|
||||
fun testSequentialPut() {
|
||||
val hSpace = DoubleHistogramSpace.fromRanges(
|
||||
val hSpace = Histogram.uniformDoubleNDFromRanges(
|
||||
(-1.0..1.0),
|
||||
(-1.0..1.0),
|
||||
(-1.0..1.0)
|
||||
@ -44,12 +47,12 @@ internal class MultivariateHistogramTest {
|
||||
put(nextDouble(), nextDouble(), nextDouble())
|
||||
}
|
||||
}
|
||||
assertEquals(n, histogram.bins.sumOf { it.value.toInt() })
|
||||
assertEquals(n, histogram.bins.sumOf { it.binValue.toInt() })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHistogramAlgebra() {
|
||||
DoubleHistogramSpace.fromRanges(
|
||||
Histogram.uniformDoubleNDFromRanges(
|
||||
(-1.0..1.0),
|
||||
(-1.0..1.0),
|
||||
(-1.0..1.0)
|
||||
@ -77,7 +80,7 @@ internal class MultivariateHistogramTest {
|
||||
assertTrue {
|
||||
res.bins.count() >= histogram1.bins.count()
|
||||
}
|
||||
assertEquals(0.0, res.bins.sumOf { it.value.toDouble() })
|
||||
assertEquals(0.0, res.bins.sumOf { it.binValue.toDouble() })
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this 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.distributions.NormalDistribution
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.stat.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)
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath 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.domains.DoubleDomain1D
|
||||
import space.kscience.kmath.domains.center
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
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 <B : ClosedRange<Double>> TreeMap<Double, B>.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<Double, ValueAndError>
|
||||
|
||||
/**
|
||||
* A histogram based on a tree map of values
|
||||
*/
|
||||
public class TreeHistogram<V : Any>(
|
||||
private val binMap: TreeMap<Double, Bin1D<Double, V>>,
|
||||
) : Histogram1D<Double, V> {
|
||||
override fun get(value: Double): Bin1D<Double, V>? = binMap.getBin(value)
|
||||
override val bins: Collection<Bin1D<Double, V>> get() = binMap.values
|
||||
}
|
||||
|
||||
/**
|
||||
* A space for univariate histograms with variable bin borders based on a tree map
|
||||
*/
|
||||
public class TreeHistogramGroup<V : Any, A>(
|
||||
public val valueAlgebra: A,
|
||||
@PublishedApi internal val binFactory: (Double) -> DoubleDomain1D,
|
||||
) : Group<TreeHistogram<V>>, ScaleOperations<TreeHistogram<V>> where A : Ring<V>, A : ScaleOperations<V> {
|
||||
|
||||
internal inner class DomainCounter(val domain: DoubleDomain1D, val counter: Counter<V> = Counter.of(valueAlgebra)) :
|
||||
ClosedRange<Double> by domain.range
|
||||
|
||||
@PublishedApi
|
||||
internal inner class TreeHistogramBuilder : Histogram1DBuilder<Double, V> {
|
||||
|
||||
override val defaultValue: V get() = valueAlgebra.one
|
||||
|
||||
private val bins: TreeMap<Double, DomainCounter> = 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<V> {
|
||||
val map = bins.mapValuesTo(TreeMap<Double, Bin1D<Double, V>>()) { (_, binCounter) ->
|
||||
Bin1D(binCounter.domain, binCounter.counter.value)
|
||||
}
|
||||
return TreeHistogram(map)
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun produce(block: Histogram1DBuilder<Double, V>.() -> Unit): TreeHistogram<V> =
|
||||
TreeHistogramBuilder().apply(block).build()
|
||||
|
||||
override fun add(
|
||||
left: TreeHistogram<V>,
|
||||
right: TreeHistogram<V>,
|
||||
): TreeHistogram<V> {
|
||||
val bins = TreeMap<Double, Bin1D<Double, V>>().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<V>, value: Double): TreeHistogram<V> {
|
||||
val bins = TreeMap<Double, Bin1D<Double, V>>().apply {
|
||||
a.bins.forEach { bin ->
|
||||
put(
|
||||
bin.domain.center,
|
||||
Bin1D(bin.domain, valueAlgebra.scale(bin.binValue, value))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return TreeHistogram(bins)
|
||||
}
|
||||
|
||||
override fun TreeHistogram<V>.unaryMinus(): TreeHistogram<V> = this * (-1)
|
||||
|
||||
override val zero: TreeHistogram<V> = produce { }
|
||||
}
|
||||
|
||||
|
||||
///**
|
||||
// * Build and fill a histogram with custom borders. Returns a read-only histogram.
|
||||
// */
|
||||
//public inline fun Histogram.custom(
|
||||
// borders: DoubleArray,
|
||||
// builder: Histogram1DBuilder<Double, Double>.() -> 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 <V : Any, A> Histogram.Companion.custom1D(
|
||||
valueAlgebra: A,
|
||||
borders: Buffer<Double>,
|
||||
): TreeHistogramGroup<V, A> where A : Ring<V>, A : ScaleOperations<V> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,171 +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.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 <B : ClosedFloatingPointRange<Double>> TreeMap<Double, B>.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(
|
||||
private val binMap: TreeMap<Double, out UnivariateBin>,
|
||||
) : UnivariateHistogram {
|
||||
override fun get(value: Double): UnivariateBin? = binMap.getBin(value)
|
||||
override val dimension: Int get() = 1
|
||||
override val bins: Collection<UnivariateBin> get() = binMap.values
|
||||
}
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
@PublishedApi
|
||||
internal class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain) : UnivariateHistogramBuilder {
|
||||
|
||||
internal class BinCounter(val domain: UnivariateDomain, val counter: Counter<Double> = Counter.double()) :
|
||||
ClosedFloatingPointRange<Double> by domain.range
|
||||
|
||||
private val bins: TreeMap<Double, BinCounter> = TreeMap()
|
||||
|
||||
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<Double>, value: Number) {
|
||||
require(point.size == 1) { "Only points with single value could be used in univariate histogram" }
|
||||
putValue(point[0], value.toDouble())
|
||||
}
|
||||
|
||||
fun build(): TreeHistogram {
|
||||
val map = bins.mapValuesTo(TreeMap<Double, UnivariateBin>()) { (_, binCounter) ->
|
||||
val count = binCounter.counter.value
|
||||
UnivariateBin(binCounter.domain, count, sqrt(count))
|
||||
}
|
||||
return TreeHistogram(map)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A space for univariate histograms with variable bin borders based on a tree map
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public class TreeHistogramSpace(
|
||||
@PublishedApi internal val binFactory: (Double) -> UnivariateDomain,
|
||||
) : Group<UnivariateHistogram>, ScaleOperations<UnivariateHistogram> {
|
||||
|
||||
public inline fun fill(block: UnivariateHistogramBuilder.() -> Unit): UnivariateHistogram =
|
||||
TreeHistogramBuilder(binFactory).apply(block).build()
|
||||
|
||||
override fun add(
|
||||
left: UnivariateHistogram,
|
||||
right: 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<Double, UnivariateBin>().apply {
|
||||
(left.bins.map { it.domain } union right.bins.map { it.domain }).forEach { def ->
|
||||
put(
|
||||
def.center,
|
||||
UnivariateBin(
|
||||
def,
|
||||
value = (left[def.center]?.value ?: 0.0) + (right[def.center]?.value ?: 0.0),
|
||||
standardDeviation = (left[def.center]?.standardDeviation
|
||||
?: 0.0) + (right[def.center]?.standardDeviation ?: 0.0)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return TreeHistogram(bins)
|
||||
}
|
||||
|
||||
override fun scale(a: UnivariateHistogram, value: Double): UnivariateHistogram {
|
||||
val bins = TreeMap<Double, UnivariateBin>().apply {
|
||||
a.bins.forEach { bin ->
|
||||
put(
|
||||
bin.domain.center,
|
||||
UnivariateBin(
|
||||
bin.domain,
|
||||
value = bin.value * value,
|
||||
standardDeviation = abs(bin.standardDeviation * value)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return TreeHistogram(bins)
|
||||
}
|
||||
|
||||
override fun UnivariateHistogram.unaryMinus(): UnivariateHistogram = this * (-1)
|
||||
|
||||
override val zero: UnivariateHistogram by lazy { fill { } }
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,79 +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.histogram
|
||||
|
||||
import space.kscience.kmath.domains.UnivariateDomain
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.asSequence
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
|
||||
|
||||
@UnstableKMathAPI
|
||||
public val UnivariateDomain.center: Double
|
||||
get() = (range.endInclusive + range.start) / 2
|
||||
|
||||
/**
|
||||
* A univariate bin based on a range
|
||||
*
|
||||
* @property value The value of histogram including weighting
|
||||
* @property 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<Double>, ClosedFloatingPointRange<Double> by domain.range {
|
||||
|
||||
override val dimension: Int get() = 1
|
||||
|
||||
override fun contains(point: Buffer<Double>): Boolean = point.size == 1 && contains(point[0])
|
||||
}
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public interface UnivariateHistogram : Histogram<Double, UnivariateBin> {
|
||||
public operator fun get(value: Double): UnivariateBin?
|
||||
override operator fun get(point: Buffer<Double>): UnivariateBin? = get(point[0])
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* Build and fill a [UnivariateHistogram]. Returns a read-only histogram.
|
||||
*/
|
||||
public inline fun uniform(
|
||||
binSize: Double,
|
||||
start: Double = 0.0,
|
||||
builder: UnivariateHistogramBuilder.() -> Unit,
|
||||
): UnivariateHistogram = TreeHistogramSpace.uniform(binSize, start).fill(builder)
|
||||
|
||||
/**
|
||||
* Build and fill a histogram with custom borders. Returns a read-only histogram.
|
||||
*/
|
||||
public inline fun custom(
|
||||
borders: DoubleArray,
|
||||
builder: UnivariateHistogramBuilder.() -> Unit,
|
||||
): UnivariateHistogram = TreeHistogramSpace.custom(borders).fill(builder)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableKMathAPI
|
||||
public interface UnivariateHistogramBuilder : HistogramBuilder<Double> {
|
||||
/**
|
||||
* Thread safe put operation
|
||||
*/
|
||||
public fun putValue(at: Double, value: Double = 1.0)
|
||||
|
||||
override fun putValue(point: Buffer<Double>, value: Number)
|
||||
}
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun UnivariateHistogramBuilder.fill(items: Iterable<Double>): Unit = items.forEach(this::putValue)
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun UnivariateHistogramBuilder.fill(array: DoubleArray): Unit = array.forEach(this::putValue)
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun UnivariateHistogramBuilder.fill(buffer: Buffer<Double>): Unit = buffer.asSequence().forEach(this::putValue)
|
@ -6,19 +6,24 @@
|
||||
package space.kscience.kmath.histogram
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.real.step
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class TreeHistogramTest {
|
||||
|
||||
@Test
|
||||
fun normalFill() {
|
||||
val histogram = UnivariateHistogram.uniform(0.1) {
|
||||
val random = Random(123)
|
||||
val histogram = Histogram.custom1D(DoubleField, 0.0..1.0 step 0.1).produce {
|
||||
repeat(100_000) {
|
||||
putValue(Random.nextDouble())
|
||||
putValue(random.nextDouble())
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue { histogram.bins.count() > 10 }
|
||||
assertTrue { histogram.bins.count() > 8}
|
||||
assertEquals(100_000, histogram.bins.sumOf { it.binValue }.toInt())
|
||||
}
|
||||
}
|
@ -7,17 +7,17 @@ Integration with [Jafama](https://github.com/jeffhain/jafama).
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-jafama:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-jafama:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -28,7 +28,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-jafama:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-jafama:0.3.0")
|
||||
}
|
||||
```
|
||||
|
||||
|
32
kmath-jupyter/README.md
Normal file
32
kmath-jupyter/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-jupyter
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-jupyter:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-jupyter:0.3.0")
|
||||
}
|
||||
```
|
4
kmath-jupyter/api/kmath-jupyter.api
Normal file
4
kmath-jupyter/api/kmath-jupyter.api
Normal file
@ -0,0 +1,4 @@
|
||||
public final class space/kscience/kmath/jupyter/KMathJupyterKt {
|
||||
public static final fun toMst (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric;
|
||||
}
|
||||
|
@ -8,17 +8,17 @@
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-kotlingrad:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -29,6 +29,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-kotlingrad:0.3.0")
|
||||
}
|
||||
```
|
||||
|
32
kmath-memory/README.md
Normal file
32
kmath-memory/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-memory
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-memory:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-memory:0.3.0")
|
||||
}
|
||||
```
|
32
kmath-multik/README.md
Normal file
32
kmath-multik/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-multik
|
||||
|
||||
JetBrains Multik connector
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-multik:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-multik:0.3.0")
|
||||
}
|
||||
```
|
@ -6,13 +6,38 @@
|
||||
package space.kscience.kmath.multik
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.one
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
|
||||
import space.kscience.kmath.tensors.core.tensorAlgebra
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
internal class MultikNDTest {
|
||||
@Test
|
||||
fun basicAlgebra(): Unit = DoubleField.multikAlgebra{
|
||||
one(2,2) + 1.0
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dotResult(){
|
||||
val dim = 100
|
||||
|
||||
val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224)
|
||||
val tensor2 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12225)
|
||||
|
||||
val multikResult = with(DoubleField.multikAlgebra){
|
||||
tensor1 dot tensor2
|
||||
}
|
||||
|
||||
val defaultResult = with(DoubleField.tensorAlgebra){
|
||||
tensor1 dot tensor2
|
||||
}
|
||||
|
||||
assertTrue {
|
||||
StructureND.contentEquals(multikResult, defaultResult)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -9,17 +9,17 @@ ND4J based implementations of KMath abstractions.
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-nd4j:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-nd4j:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -30,7 +30,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-nd4j:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-nd4j:0.3.0")
|
||||
}
|
||||
```
|
||||
|
||||
|
32
kmath-optimization/README.md
Normal file
32
kmath-optimization/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-optimization
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-optimization:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-optimization:0.3.0")
|
||||
}
|
||||
```
|
32
kmath-stat/README.md
Normal file
32
kmath-stat/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-stat
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-stat:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-stat:0.3.0")
|
||||
}
|
||||
```
|
@ -27,7 +27,7 @@ public interface Distribution<T : Any> : Sampler<T> {
|
||||
public companion object
|
||||
}
|
||||
|
||||
public interface UnivariateDistribution<T : Comparable<T>> : Distribution<T> {
|
||||
public interface Distribution1D<T : Comparable<T>> : Distribution<T> {
|
||||
/**
|
||||
* Cumulative distribution for ordered parameter (CDF)
|
||||
*/
|
||||
@ -37,7 +37,7 @@ public interface UnivariateDistribution<T : Comparable<T>> : Distribution<T> {
|
||||
/**
|
||||
* Compute probability integral in an interval
|
||||
*/
|
||||
public fun <T : Comparable<T>> UnivariateDistribution<T>.integral(from: T, to: T): Double {
|
||||
public fun <T : Comparable<T>> Distribution1D<T>.integral(from: T, to: T): Double {
|
||||
require(to > from)
|
||||
return cumulative(to) - cumulative(from)
|
||||
}
|
||||
|
@ -14,14 +14,9 @@ import space.kscience.kmath.stat.RandomGenerator
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
* Implements [UnivariateDistribution] for the normal (gaussian) distribution.
|
||||
* Implements [Distribution1D] for the normal (gaussian) distribution.
|
||||
*/
|
||||
public class NormalDistribution(public val sampler: GaussianSampler) : UnivariateDistribution<Double> {
|
||||
public constructor(
|
||||
mean: Double,
|
||||
standardDeviation: Double,
|
||||
normalized: NormalizedGaussianSampler = ZigguratNormalizedGaussianSampler,
|
||||
) : this(GaussianSampler(mean, standardDeviation, normalized))
|
||||
public class NormalDistribution(public val sampler: GaussianSampler) : Distribution1D<Double> {
|
||||
|
||||
override fun probability(arg: Double): Double {
|
||||
val x1 = (arg - sampler.mean) / sampler.standardDeviation
|
||||
@ -43,3 +38,9 @@ public class NormalDistribution(public val sampler: GaussianSampler) : Univariat
|
||||
private val SQRT2 = sqrt(2.0)
|
||||
}
|
||||
}
|
||||
|
||||
public fun NormalDistribution(
|
||||
mean: Double,
|
||||
standardDeviation: Double,
|
||||
normalized: NormalizedGaussianSampler = ZigguratNormalizedGaussianSampler,
|
||||
): NormalDistribution = NormalDistribution(GaussianSampler(mean, standardDeviation, normalized))
|
||||
|
@ -67,3 +67,12 @@ public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int):
|
||||
@JvmName("sampleIntBuffer")
|
||||
public fun Sampler<Int>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Int>> =
|
||||
sampleBuffer(generator, size, ::IntBuffer)
|
||||
|
||||
|
||||
/**
|
||||
* Samples a [Buffer] of values from this [Sampler].
|
||||
*/
|
||||
public suspend fun Sampler<Double>.nextBuffer(generator: RandomGenerator, size: Int): Buffer<Double> =
|
||||
sampleBuffer(generator, size).first()
|
||||
|
||||
//TODO add `context(RandomGenerator) Sampler.nextBuffer
|
@ -8,9 +8,9 @@ package space.kscience.kmath.stat
|
||||
import space.kscience.kmath.chains.Chain
|
||||
import space.kscience.kmath.chains.SimpleChain
|
||||
import space.kscience.kmath.distributions.Distribution
|
||||
import space.kscience.kmath.distributions.UnivariateDistribution
|
||||
import space.kscience.kmath.distributions.Distribution1D
|
||||
|
||||
public class UniformDistribution(public val range: ClosedFloatingPointRange<Double>) : UnivariateDistribution<Double> {
|
||||
public class UniformDistribution(public val range: ClosedFloatingPointRange<Double>) : Distribution1D<Double> {
|
||||
private val length: Double = range.endInclusive - range.start
|
||||
|
||||
override fun probability(arg: Double): Double = if (arg in range) 1.0 / length else 0.0
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this 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<ValueAndError> {
|
||||
|
||||
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))
|
||||
}
|
32
kmath-symja/README.md
Normal file
32
kmath-symja/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-symja
|
||||
|
||||
Symja integration module
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-symja:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-symja:0.3.0")
|
||||
}
|
||||
```
|
32
kmath-tensorflow/README.md
Normal file
32
kmath-tensorflow/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module kmath-tensorflow
|
||||
|
||||
Google tensorflow connector
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-tensorflow:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-tensorflow:0.3.0")
|
||||
}
|
||||
```
|
@ -6,11 +6,9 @@ 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.Constant
|
||||
import org.tensorflow.op.core.Max
|
||||
import org.tensorflow.op.core.Min
|
||||
import org.tensorflow.op.core.Sum
|
||||
import org.tensorflow.op.core.*
|
||||
import org.tensorflow.types.TInt32
|
||||
import org.tensorflow.types.family.TNumber
|
||||
import org.tensorflow.types.family.TType
|
||||
@ -182,7 +180,7 @@ public abstract class TensorFlowAlgebra<T, TT : TNumber, A : Ring<T>> internal c
|
||||
override fun StructureND<T>.unaryMinus(): TensorFlowOutput<T, TT> = operate(ops.math::neg)
|
||||
|
||||
override fun Tensor<T>.get(i: Int): Tensor<T> = operate {
|
||||
TODO("Not yet implemented")
|
||||
StridedSliceHelper.stridedSlice(ops.scope(), it, Indices.at(i.toLong()))
|
||||
}
|
||||
|
||||
override fun Tensor<T>.transpose(i: Int, j: Int): Tensor<T> = operate {
|
||||
@ -210,7 +208,13 @@ public abstract class TensorFlowAlgebra<T, TT : TNumber, A : Ring<T>> internal c
|
||||
dim1: Int,
|
||||
dim2: Int,
|
||||
): TensorFlowOutput<T, TT> = diagonalEntries.operate {
|
||||
TODO("Not yet implemented")
|
||||
ops.linalg.matrixDiagV3(
|
||||
/* diagonal = */ it,
|
||||
/* k = */ ops.constant(offset),
|
||||
/* numRows = */ ops.constant(dim1),
|
||||
/* numCols = */ ops.constant(dim2),
|
||||
/* paddingValue = */ const(elementAlgebra.zero)
|
||||
)
|
||||
}
|
||||
|
||||
override fun StructureND<T>.sum(): T = operate {
|
||||
|
@ -6,7 +6,6 @@ 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 kotlin.random.Random
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class DoubleTensorFlowOps {
|
||||
@ -23,7 +22,6 @@ class DoubleTensorFlowOps {
|
||||
|
||||
@Test
|
||||
fun dot(){
|
||||
val random = Random(12224)
|
||||
val dim = 1000
|
||||
|
||||
val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224)
|
||||
|
@ -9,17 +9,17 @@ Common linear algebra operations on tensors.
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-17`.
|
||||
The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-tensors:0.3.0-dev-17'
|
||||
implementation 'space.kscience:kmath-tensors:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
@ -30,6 +30,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-tensors:0.3.0-dev-17")
|
||||
implementation("space.kscience:kmath-tensors:0.3.0")
|
||||
}
|
||||
```
|
||||
|
@ -27,7 +27,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
||||
val newThis = broadcast[0]
|
||||
val newOther = broadcast[1]
|
||||
val resBuffer = DoubleArray(newThis.indices.linearSize) { i ->
|
||||
newThis.mutableBuffer.array()[i] + newOther.mutableBuffer.array()[i]
|
||||
newThis.mutableBuffer[i] + newOther.mutableBuffer[i]
|
||||
}
|
||||
return DoubleTensor(newThis.shape, resBuffer)
|
||||
}
|
||||
@ -35,8 +35,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
||||
override fun Tensor<Double>.plusAssign(arg: StructureND<Double>) {
|
||||
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
||||
for (i in 0 until tensor.indices.linearSize) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] +=
|
||||
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] +=
|
||||
newOther.mutableBuffer[tensor.bufferStart + i]
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
||||
val newThis = broadcast[0]
|
||||
val newOther = broadcast[1]
|
||||
val resBuffer = DoubleArray(newThis.indices.linearSize) { i ->
|
||||
newThis.mutableBuffer.array()[i] - newOther.mutableBuffer.array()[i]
|
||||
newThis.mutableBuffer[i] - newOther.mutableBuffer[i]
|
||||
}
|
||||
return DoubleTensor(newThis.shape, resBuffer)
|
||||
}
|
||||
@ -53,8 +53,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
||||
override fun Tensor<Double>.minusAssign(arg: StructureND<Double>) {
|
||||
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
||||
for (i in 0 until tensor.indices.linearSize) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] -=
|
||||
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] -=
|
||||
newOther.mutableBuffer[tensor.bufferStart + i]
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,8 +63,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
||||
val newThis = broadcast[0]
|
||||
val newOther = broadcast[1]
|
||||
val resBuffer = DoubleArray(newThis.indices.linearSize) { i ->
|
||||
newThis.mutableBuffer.array()[newThis.bufferStart + i] *
|
||||
newOther.mutableBuffer.array()[newOther.bufferStart + i]
|
||||
newThis.mutableBuffer[newThis.bufferStart + i] *
|
||||
newOther.mutableBuffer[newOther.bufferStart + i]
|
||||
}
|
||||
return DoubleTensor(newThis.shape, resBuffer)
|
||||
}
|
||||
@ -72,8 +72,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
||||
override fun Tensor<Double>.timesAssign(arg: StructureND<Double>) {
|
||||
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
||||
for (i in 0 until tensor.indices.linearSize) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] *=
|
||||
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] *=
|
||||
newOther.mutableBuffer[tensor.bufferStart + i]
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,8 +82,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
||||
val newThis = broadcast[0]
|
||||
val newOther = broadcast[1]
|
||||
val resBuffer = DoubleArray(newThis.indices.linearSize) { i ->
|
||||
newThis.mutableBuffer.array()[newOther.bufferStart + i] /
|
||||
newOther.mutableBuffer.array()[newOther.bufferStart + i]
|
||||
newThis.mutableBuffer[newOther.bufferStart + i] /
|
||||
newOther.mutableBuffer[newOther.bufferStart + i]
|
||||
}
|
||||
return DoubleTensor(newThis.shape, resBuffer)
|
||||
}
|
||||
@ -91,8 +91,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
||||
override fun Tensor<Double>.divAssign(arg: StructureND<Double>) {
|
||||
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
||||
for (i in 0 until tensor.indices.linearSize) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] /=
|
||||
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] /=
|
||||
newOther.mutableBuffer[tensor.bufferStart + i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public open class DoubleTensorAlgebra :
|
||||
}
|
||||
|
||||
override fun StructureND<Double>.valueOrNull(): Double? = if (tensor.shape contentEquals intArrayOf(1))
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart] else null
|
||||
tensor.mutableBuffer[tensor.bufferStart] else null
|
||||
|
||||
override fun StructureND<Double>.value(): Double = valueOrNull()
|
||||
?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]")
|
||||
@ -208,7 +208,7 @@ public open class DoubleTensorAlgebra :
|
||||
|
||||
override fun Double.plus(arg: StructureND<Double>): DoubleTensor {
|
||||
val resBuffer = DoubleArray(arg.tensor.numElements) { i ->
|
||||
arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + this
|
||||
arg.tensor.mutableBuffer[arg.tensor.bufferStart + i] + this
|
||||
}
|
||||
return DoubleTensor(arg.shape, resBuffer)
|
||||
}
|
||||
@ -218,35 +218,35 @@ public open class DoubleTensorAlgebra :
|
||||
override fun StructureND<Double>.plus(arg: StructureND<Double>): DoubleTensor {
|
||||
checkShapesCompatible(tensor, arg.tensor)
|
||||
val resBuffer = DoubleArray(tensor.numElements) { i ->
|
||||
tensor.mutableBuffer.array()[i] + arg.tensor.mutableBuffer.array()[i]
|
||||
tensor.mutableBuffer[i] + arg.tensor.mutableBuffer[i]
|
||||
}
|
||||
return DoubleTensor(tensor.shape, resBuffer)
|
||||
}
|
||||
|
||||
override fun Tensor<Double>.plusAssign(value: Double) {
|
||||
for (i in 0 until tensor.numElements) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] += value
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] += value
|
||||
}
|
||||
}
|
||||
|
||||
override fun Tensor<Double>.plusAssign(arg: StructureND<Double>) {
|
||||
checkShapesCompatible(tensor, arg.tensor)
|
||||
for (i in 0 until tensor.numElements) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] +=
|
||||
arg.tensor.mutableBuffer.array()[tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] +=
|
||||
arg.tensor.mutableBuffer[tensor.bufferStart + i]
|
||||
}
|
||||
}
|
||||
|
||||
override fun Double.minus(arg: StructureND<Double>): DoubleTensor {
|
||||
val resBuffer = DoubleArray(arg.tensor.numElements) { i ->
|
||||
this - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i]
|
||||
this - arg.tensor.mutableBuffer[arg.tensor.bufferStart + i]
|
||||
}
|
||||
return DoubleTensor(arg.shape, resBuffer)
|
||||
}
|
||||
|
||||
override fun StructureND<Double>.minus(arg: Double): DoubleTensor {
|
||||
val resBuffer = DoubleArray(tensor.numElements) { i ->
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] - arg
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] - arg
|
||||
}
|
||||
return DoubleTensor(tensor.shape, resBuffer)
|
||||
}
|
||||
@ -254,28 +254,28 @@ public open class DoubleTensorAlgebra :
|
||||
override fun StructureND<Double>.minus(arg: StructureND<Double>): DoubleTensor {
|
||||
checkShapesCompatible(tensor, arg)
|
||||
val resBuffer = DoubleArray(tensor.numElements) { i ->
|
||||
tensor.mutableBuffer.array()[i] - arg.tensor.mutableBuffer.array()[i]
|
||||
tensor.mutableBuffer[i] - arg.tensor.mutableBuffer[i]
|
||||
}
|
||||
return DoubleTensor(tensor.shape, resBuffer)
|
||||
}
|
||||
|
||||
override fun Tensor<Double>.minusAssign(value: Double) {
|
||||
for (i in 0 until tensor.numElements) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] -= value
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] -= value
|
||||
}
|
||||
}
|
||||
|
||||
override fun Tensor<Double>.minusAssign(arg: StructureND<Double>) {
|
||||
checkShapesCompatible(tensor, arg)
|
||||
for (i in 0 until tensor.numElements) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] -=
|
||||
arg.tensor.mutableBuffer.array()[tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] -=
|
||||
arg.tensor.mutableBuffer[tensor.bufferStart + i]
|
||||
}
|
||||
}
|
||||
|
||||
override fun Double.times(arg: StructureND<Double>): DoubleTensor {
|
||||
val resBuffer = DoubleArray(arg.tensor.numElements) { i ->
|
||||
arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] * this
|
||||
arg.tensor.mutableBuffer[arg.tensor.bufferStart + i] * this
|
||||
}
|
||||
return DoubleTensor(arg.shape, resBuffer)
|
||||
}
|
||||
@ -285,36 +285,36 @@ public open class DoubleTensorAlgebra :
|
||||
override fun StructureND<Double>.times(arg: StructureND<Double>): DoubleTensor {
|
||||
checkShapesCompatible(tensor, arg)
|
||||
val resBuffer = DoubleArray(tensor.numElements) { i ->
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] *
|
||||
arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] *
|
||||
arg.tensor.mutableBuffer[arg.tensor.bufferStart + i]
|
||||
}
|
||||
return DoubleTensor(tensor.shape, resBuffer)
|
||||
}
|
||||
|
||||
override fun Tensor<Double>.timesAssign(value: Double) {
|
||||
for (i in 0 until tensor.numElements) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] *= value
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] *= value
|
||||
}
|
||||
}
|
||||
|
||||
override fun Tensor<Double>.timesAssign(arg: StructureND<Double>) {
|
||||
checkShapesCompatible(tensor, arg)
|
||||
for (i in 0 until tensor.numElements) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] *=
|
||||
arg.tensor.mutableBuffer.array()[tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] *=
|
||||
arg.tensor.mutableBuffer[tensor.bufferStart + i]
|
||||
}
|
||||
}
|
||||
|
||||
override fun Double.div(arg: StructureND<Double>): DoubleTensor {
|
||||
val resBuffer = DoubleArray(arg.tensor.numElements) { i ->
|
||||
this / arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i]
|
||||
this / arg.tensor.mutableBuffer[arg.tensor.bufferStart + i]
|
||||
}
|
||||
return DoubleTensor(arg.shape, resBuffer)
|
||||
}
|
||||
|
||||
override fun StructureND<Double>.div(arg: Double): DoubleTensor {
|
||||
val resBuffer = DoubleArray(tensor.numElements) { i ->
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] / arg
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] / arg
|
||||
}
|
||||
return DoubleTensor(shape, resBuffer)
|
||||
}
|
||||
@ -322,29 +322,29 @@ public open class DoubleTensorAlgebra :
|
||||
override fun StructureND<Double>.div(arg: StructureND<Double>): DoubleTensor {
|
||||
checkShapesCompatible(tensor, arg)
|
||||
val resBuffer = DoubleArray(tensor.numElements) { i ->
|
||||
tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] /
|
||||
arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[arg.tensor.bufferStart + i] /
|
||||
arg.tensor.mutableBuffer[arg.tensor.bufferStart + i]
|
||||
}
|
||||
return DoubleTensor(tensor.shape, resBuffer)
|
||||
}
|
||||
|
||||
override fun Tensor<Double>.divAssign(value: Double) {
|
||||
for (i in 0 until tensor.numElements) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] /= value
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] /= value
|
||||
}
|
||||
}
|
||||
|
||||
override fun Tensor<Double>.divAssign(arg: StructureND<Double>) {
|
||||
checkShapesCompatible(tensor, arg)
|
||||
for (i in 0 until tensor.numElements) {
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] /=
|
||||
arg.tensor.mutableBuffer.array()[tensor.bufferStart + i]
|
||||
tensor.mutableBuffer[tensor.bufferStart + i] /=
|
||||
arg.tensor.mutableBuffer[tensor.bufferStart + i]
|
||||
}
|
||||
}
|
||||
|
||||
override fun StructureND<Double>.unaryMinus(): DoubleTensor {
|
||||
val resBuffer = DoubleArray(tensor.numElements) { i ->
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + i].unaryMinus()
|
||||
tensor.mutableBuffer[tensor.bufferStart + i].unaryMinus()
|
||||
}
|
||||
return DoubleTensor(tensor.shape, resBuffer)
|
||||
}
|
||||
@ -367,8 +367,8 @@ public open class DoubleTensorAlgebra :
|
||||
newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] }
|
||||
|
||||
val linearIndex = resTensor.indices.offset(newMultiIndex)
|
||||
resTensor.mutableBuffer.array()[linearIndex] =
|
||||
tensor.mutableBuffer.array()[tensor.bufferStart + offset]
|
||||
resTensor.mutableBuffer[linearIndex] =
|
||||
tensor.mutableBuffer[tensor.bufferStart + offset]
|
||||
}
|
||||
return resTensor
|
||||
}
|
||||
@ -833,8 +833,38 @@ public open class DoubleTensorAlgebra :
|
||||
return qTensor to rTensor
|
||||
}
|
||||
|
||||
override fun StructureND<Double>.svd(): Triple<DoubleTensor, DoubleTensor, DoubleTensor> =
|
||||
svd(epsilon = 1e-10)
|
||||
override fun StructureND<Double>.svd(): Triple<DoubleTensor, DoubleTensor, DoubleTensor> {
|
||||
return this.svdGolubKahan()
|
||||
}
|
||||
|
||||
public fun StructureND<Double>.svdGolubKahan(iterations: Int = 30, epsilon: Double = 1e-10): Triple<DoubleTensor, DoubleTensor, DoubleTensor> {
|
||||
val size = tensor.dimension
|
||||
val commonShape = tensor.shape.sliceArray(0 until size - 2)
|
||||
val (n, m) = tensor.shape.sliceArray(size - 2 until size)
|
||||
val uTensor = zeros(commonShape + intArrayOf(n, m))
|
||||
val sTensor = zeros(commonShape + intArrayOf(m))
|
||||
val vTensor = zeros(commonShape + intArrayOf(m, m))
|
||||
|
||||
val matrices = tensor.matrices
|
||||
val uTensors = uTensor.matrices
|
||||
val sTensorVectors = sTensor.vectors
|
||||
val vTensors = vTensor.matrices
|
||||
|
||||
for (index in matrices.indices) {
|
||||
val matrix = matrices[index]
|
||||
val matrixSize = matrix.shape.reduce { acc, i -> acc * i }
|
||||
val curMatrix = DoubleTensor(
|
||||
matrix.shape,
|
||||
matrix.mutableBuffer.array()
|
||||
.slice(matrix.bufferStart until matrix.bufferStart + matrixSize)
|
||||
.toDoubleArray()
|
||||
)
|
||||
curMatrix.as2D().svdGolubKahanHelper(uTensors[index].as2D(), sTensorVectors[index], vTensors[index].as2D(),
|
||||
iterations, epsilon)
|
||||
}
|
||||
|
||||
return Triple(uTensor, sTensor, vTensor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Singular Value Decomposition.
|
||||
@ -849,7 +879,7 @@ public open class DoubleTensorAlgebra :
|
||||
* i.e., the precision with which the cosine approaches 1 in an iterative algorithm.
|
||||
* @return a triple `Triple(U, S, V)`.
|
||||
*/
|
||||
public fun StructureND<Double>.svd(epsilon: Double): Triple<DoubleTensor, DoubleTensor, DoubleTensor> {
|
||||
public fun StructureND<Double>.svdPowerMethod(epsilon: Double = 1e-10): Triple<DoubleTensor, DoubleTensor, DoubleTensor> {
|
||||
val size = tensor.dimension
|
||||
val commonShape = tensor.shape.sliceArray(0 until size - 2)
|
||||
val (n, m) = tensor.shape.sliceArray(size - 2 until size)
|
||||
@ -876,7 +906,7 @@ public open class DoubleTensorAlgebra :
|
||||
.slice(matrix.bufferStart until matrix.bufferStart + matrixSize)
|
||||
.toDoubleArray()
|
||||
)
|
||||
svdHelper(curMatrix, usv, m, n, epsilon)
|
||||
svdPowerMethodHelper(curMatrix, usv, m, n, epsilon)
|
||||
}
|
||||
|
||||
return Triple(uTensor.transpose(), sTensor, vTensor.transpose())
|
||||
@ -907,7 +937,7 @@ public open class DoubleTensorAlgebra :
|
||||
}
|
||||
}
|
||||
|
||||
val (u, s, v) = tensor.svd(epsilon)
|
||||
val (u, s, v) = tensor.svd()
|
||||
val shp = s.shape + intArrayOf(1)
|
||||
val utv = u.transpose() dot v
|
||||
val n = s.shape.last()
|
||||
@ -928,18 +958,21 @@ public open class DoubleTensorAlgebra :
|
||||
|
||||
var eigenvalueStart = 0
|
||||
var eigenvectorStart = 0
|
||||
val eigenvaluesBuffer = eigenvalues.mutableBuffer
|
||||
val eigenvectorsBuffer = eigenvectors.mutableBuffer
|
||||
|
||||
for (matrix in tensor.matrixSequence()) {
|
||||
val matrix2D = matrix.as2D()
|
||||
val (d, v) = matrix2D.jacobiHelper(maxIteration, epsilon)
|
||||
|
||||
for (i in 0 until matrix2D.rowNum) {
|
||||
for (j in 0 until matrix2D.colNum) {
|
||||
eigenvectors.mutableBuffer.array()[eigenvectorStart + i * matrix2D.rowNum + j] = v[i, j]
|
||||
eigenvectorsBuffer[eigenvectorStart + i * matrix2D.rowNum + j] = v[i, j]
|
||||
}
|
||||
}
|
||||
|
||||
for (i in 0 until matrix2D.rowNum) {
|
||||
eigenvalues.mutableBuffer.array()[eigenvalueStart + i] = d[i]
|
||||
eigenvaluesBuffer[eigenvalueStart + i] = d[i]
|
||||
}
|
||||
|
||||
eigenvalueStart += this.shape.last()
|
||||
@ -962,11 +995,11 @@ public open class DoubleTensorAlgebra :
|
||||
|
||||
// assume that buffered tensor is square matrix
|
||||
operator fun BufferedTensor<Double>.get(i: Int, j: Int): Double {
|
||||
return this.mutableBuffer.array()[bufferStart + i * this.shape[0] + j]
|
||||
return this.mutableBuffer[bufferStart + i * this.shape[0] + j]
|
||||
}
|
||||
|
||||
operator fun BufferedTensor<Double>.set(i: Int, j: Int, value: Double) {
|
||||
this.mutableBuffer.array()[bufferStart + i * this.shape[0] + j] = value
|
||||
this.mutableBuffer[bufferStart + i * this.shape[0] + j] = value
|
||||
}
|
||||
|
||||
fun maxOffDiagonal(matrix: BufferedTensor<Double>): Double {
|
||||
|
@ -17,6 +17,7 @@ import space.kscience.kmath.tensors.core.DoubleTensor
|
||||
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
|
||||
import space.kscience.kmath.tensors.core.IntTensor
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@ -299,7 +300,7 @@ internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun DoubleTensorAlgebra.svdHelper(
|
||||
internal fun DoubleTensorAlgebra.svdPowerMethodHelper(
|
||||
matrix: DoubleTensor,
|
||||
USV: Triple<BufferedTensor<Double>, BufferedTensor<Double>, BufferedTensor<Double>>,
|
||||
m: Int, n: Int, epsilon: Double,
|
||||
@ -307,6 +308,14 @@ internal fun DoubleTensorAlgebra.svdHelper(
|
||||
val res = ArrayList<Triple<Double, DoubleTensor, DoubleTensor>>(0)
|
||||
val (matrixU, matrixS, matrixV) = USV
|
||||
|
||||
val matrixUStart = matrixU.bufferStart
|
||||
val matrixSStart = matrixS.bufferStart
|
||||
val matrixVStart = matrixV.bufferStart
|
||||
|
||||
val matrixUBuffer = matrixU.mutableBuffer
|
||||
val matrixSBuffer = matrixS.mutableBuffer
|
||||
val matrixVBuffer = matrixV.mutableBuffer
|
||||
|
||||
for (k in 0 until min(n, m)) {
|
||||
var a = matrix.copy()
|
||||
for ((singularValue, u, v) in res.slice(0 until k)) {
|
||||
@ -340,12 +349,307 @@ internal fun DoubleTensorAlgebra.svdHelper(
|
||||
val uBuffer = res.map { it.second }.flatMap { it.mutableBuffer.array().toList() }.toDoubleArray()
|
||||
val vBuffer = res.map { it.third }.flatMap { it.mutableBuffer.array().toList() }.toDoubleArray()
|
||||
for (i in uBuffer.indices) {
|
||||
matrixU.mutableBuffer.array()[matrixU.bufferStart + i] = uBuffer[i]
|
||||
matrixUBuffer[matrixUStart + i] = uBuffer[i]
|
||||
}
|
||||
for (i in s.indices) {
|
||||
matrixS.mutableBuffer.array()[matrixS.bufferStart + i] = s[i]
|
||||
matrixSBuffer[matrixSStart + i] = s[i]
|
||||
}
|
||||
for (i in vBuffer.indices) {
|
||||
matrixV.mutableBuffer.array()[matrixV.bufferStart + i] = vBuffer[i]
|
||||
matrixVBuffer[matrixVStart + i] = vBuffer[i]
|
||||
}
|
||||
}
|
||||
|
||||
private fun pythag(a: Double, b: Double): Double {
|
||||
val at: Double = abs(a)
|
||||
val bt: Double = abs(b)
|
||||
val ct: Double
|
||||
val result: Double
|
||||
if (at > bt) {
|
||||
ct = bt / at
|
||||
result = at * sqrt(1.0 + ct * ct)
|
||||
} else if (bt > 0.0) {
|
||||
ct = at / bt
|
||||
result = bt * sqrt(1.0 + ct * ct)
|
||||
} else result = 0.0
|
||||
return result
|
||||
}
|
||||
|
||||
private fun SIGN(a: Double, b: Double): Double {
|
||||
if (b >= 0.0)
|
||||
return abs(a)
|
||||
else
|
||||
return -abs(a)
|
||||
}
|
||||
internal fun MutableStructure2D<Double>.svdGolubKahanHelper(u: MutableStructure2D<Double>, w: BufferedTensor<Double>,
|
||||
v: MutableStructure2D<Double>, iterations: Int, epsilon: Double) {
|
||||
val shape = this.shape
|
||||
val m = shape.component1()
|
||||
val n = shape.component2()
|
||||
var f = 0.0
|
||||
val rv1 = DoubleArray(n)
|
||||
var s = 0.0
|
||||
var scale = 0.0
|
||||
var anorm = 0.0
|
||||
var g = 0.0
|
||||
var l = 0
|
||||
|
||||
val wStart = w.bufferStart
|
||||
val wBuffer = w.mutableBuffer
|
||||
|
||||
for (i in 0 until n) {
|
||||
/* left-hand reduction */
|
||||
l = i + 1
|
||||
rv1[i] = scale * g
|
||||
g = 0.0
|
||||
s = 0.0
|
||||
scale = 0.0
|
||||
if (i < m) {
|
||||
for (k in i until m) {
|
||||
scale += abs(this[k, i]);
|
||||
}
|
||||
if (abs(scale) > epsilon) {
|
||||
for (k in i until m) {
|
||||
this[k, i] = (this[k, i] / scale)
|
||||
s += this[k, i] * this[k, i]
|
||||
}
|
||||
f = this[i, i]
|
||||
if (f >= 0) {
|
||||
g = (-1) * abs(sqrt(s))
|
||||
} else {
|
||||
g = abs(sqrt(s))
|
||||
}
|
||||
val h = f * g - s
|
||||
this[i, i] = f - g
|
||||
if (i != n - 1) {
|
||||
for (j in l until n) {
|
||||
s = 0.0
|
||||
for (k in i until m) {
|
||||
s += this[k, i] * this[k, j]
|
||||
}
|
||||
f = s / h
|
||||
for (k in i until m) {
|
||||
this[k, j] += f * this[k, i]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k in i until m) {
|
||||
this[k, i] = this[k, i] * scale
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wBuffer[wStart + i] = scale * g
|
||||
/* right-hand reduction */
|
||||
g = 0.0
|
||||
s = 0.0
|
||||
scale = 0.0
|
||||
if (i < m && i != n - 1) {
|
||||
for (k in l until n) {
|
||||
scale += abs(this[i, k])
|
||||
}
|
||||
if (abs(scale) > epsilon) {
|
||||
for (k in l until n) {
|
||||
this[i, k] = this[i, k] / scale
|
||||
s += this[i, k] * this[i, k]
|
||||
}
|
||||
f = this[i, l]
|
||||
if (f >= 0) {
|
||||
g = (-1) * abs(sqrt(s))
|
||||
} else {
|
||||
g = abs(sqrt(s))
|
||||
}
|
||||
val h = f * g - s
|
||||
this[i, l] = f - g
|
||||
for (k in l until n) {
|
||||
rv1[k] = this[i, k] / h
|
||||
}
|
||||
if (i != m - 1) {
|
||||
for (j in l until m) {
|
||||
s = 0.0
|
||||
for (k in l until n) {
|
||||
s += this[j, k] * this[i, k]
|
||||
}
|
||||
for (k in l until n) {
|
||||
this[j, k] += s * rv1[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k in l until n) {
|
||||
this[i, k] = this[i, k] * scale
|
||||
}
|
||||
}
|
||||
}
|
||||
anorm = max(anorm, (abs(wBuffer[wStart + i]) + abs(rv1[i])));
|
||||
}
|
||||
|
||||
for (i in n - 1 downTo 0) {
|
||||
if (i < n - 1) {
|
||||
if (abs(g) > epsilon) {
|
||||
for (j in l until n) {
|
||||
v[j, i] = (this[i, j] / this[i, l]) / g
|
||||
}
|
||||
for (j in l until n) {
|
||||
s = 0.0
|
||||
for (k in l until n)
|
||||
s += this[i, k] * v[k, j]
|
||||
for (k in l until n)
|
||||
v[k, j] += s * v[k, i]
|
||||
}
|
||||
}
|
||||
for (j in l until n) {
|
||||
v[i, j] = 0.0
|
||||
v[j, i] = 0.0
|
||||
}
|
||||
}
|
||||
v[i, i] = 1.0
|
||||
g = rv1[i]
|
||||
l = i
|
||||
}
|
||||
|
||||
for (i in min(n, m) - 1 downTo 0) {
|
||||
l = i + 1
|
||||
g = wBuffer[wStart + i]
|
||||
for (j in l until n) {
|
||||
this[i, j] = 0.0
|
||||
}
|
||||
if (abs(g) > epsilon) {
|
||||
g = 1.0 / g
|
||||
for (j in l until n) {
|
||||
s = 0.0
|
||||
for (k in l until m) {
|
||||
s += this[k, i] * this[k, j]
|
||||
}
|
||||
f = (s / this[i, i]) * g
|
||||
for (k in i until m) {
|
||||
this[k, j] += f * this[k, i]
|
||||
}
|
||||
}
|
||||
for (j in i until m) {
|
||||
this[j, i] *= g
|
||||
}
|
||||
} else {
|
||||
for (j in i until m) {
|
||||
this[j, i] = 0.0
|
||||
}
|
||||
}
|
||||
this[i, i] += 1.0
|
||||
}
|
||||
|
||||
var flag = 0
|
||||
var nm = 0
|
||||
var c = 0.0
|
||||
var h = 0.0
|
||||
var y = 0.0
|
||||
var z = 0.0
|
||||
var x = 0.0
|
||||
for (k in n - 1 downTo 0) {
|
||||
for (its in 1 until iterations) {
|
||||
flag = 1
|
||||
for (newl in k downTo 0) {
|
||||
nm = newl - 1
|
||||
if (abs(rv1[newl]) + anorm == anorm) {
|
||||
flag = 0
|
||||
l = newl
|
||||
break
|
||||
}
|
||||
if (abs(wBuffer[wStart + nm]) + anorm == anorm) {
|
||||
l = newl
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (flag != 0) {
|
||||
c = 0.0
|
||||
s = 1.0
|
||||
for (i in l until k + 1) {
|
||||
f = s * rv1[i]
|
||||
rv1[i] = c * rv1[i]
|
||||
if (abs(f) + anorm == anorm) {
|
||||
break
|
||||
}
|
||||
g = wBuffer[wStart + i]
|
||||
h = pythag(f, g)
|
||||
wBuffer[wStart + i] = h
|
||||
h = 1.0 / h
|
||||
c = g * h
|
||||
s = (-f) * h
|
||||
for (j in 0 until m) {
|
||||
y = this[j, nm]
|
||||
z = this[j, i]
|
||||
this[j, nm] = y * c + z * s
|
||||
this[j, i] = z * c - y * s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
z = wBuffer[wStart + k]
|
||||
if (l == k) {
|
||||
if (z < 0.0) {
|
||||
wBuffer[wStart + k] = -z
|
||||
for (j in 0 until n)
|
||||
v[j, k] = -v[j, k]
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
x = wBuffer[wStart + l]
|
||||
nm = k - 1
|
||||
y = wBuffer[wStart + nm]
|
||||
g = rv1[nm]
|
||||
h = rv1[k]
|
||||
f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y)
|
||||
g = pythag(f, 1.0)
|
||||
f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x
|
||||
c = 1.0
|
||||
s = 1.0
|
||||
|
||||
var i = 0
|
||||
for (j in l until nm + 1) {
|
||||
i = j + 1
|
||||
g = rv1[i]
|
||||
y = wBuffer[wStart + i]
|
||||
h = s * g
|
||||
g = c * g
|
||||
z = pythag(f, h)
|
||||
rv1[j] = z
|
||||
c = f / z
|
||||
s = h / z
|
||||
f = x * c + g * s
|
||||
g = g * c - x * s
|
||||
h = y * s
|
||||
y *= c
|
||||
|
||||
for (jj in 0 until n) {
|
||||
x = v[jj, j];
|
||||
z = v[jj, i];
|
||||
v[jj, j] = x * c + z * s;
|
||||
v[jj, i] = z * c - x * s;
|
||||
}
|
||||
z = pythag(f, h)
|
||||
wBuffer[wStart + j] = z
|
||||
if (abs(z) > epsilon) {
|
||||
z = 1.0 / z
|
||||
c = f * z
|
||||
s = h * z
|
||||
}
|
||||
f = c * g + s * y
|
||||
x = c * y - s * g
|
||||
for (jj in 0 until m) {
|
||||
y = this[jj, j]
|
||||
z = this[jj, i]
|
||||
this[jj, j] = y * c + z * s
|
||||
this[jj, i] = z * c - y * s
|
||||
}
|
||||
}
|
||||
rv1[l] = 0.0
|
||||
rv1[k] = f
|
||||
wBuffer[wStart + k] = x
|
||||
}
|
||||
}
|
||||
|
||||
for (i in 0 until n) {
|
||||
for (j in 0 until m) {
|
||||
u[j, i] = this[j, i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,23 +156,12 @@ internal class TestDoubleLinearOpsTensorAlgebra {
|
||||
|
||||
val res = svd1d(tensor2)
|
||||
|
||||
val resBuffer = res.mutableBuffer
|
||||
val resStart = res.bufferStart
|
||||
|
||||
assertTrue(res.shape contentEquals intArrayOf(2))
|
||||
assertTrue { abs(abs(res.mutableBuffer.array()[res.bufferStart]) - 0.386) < 0.01 }
|
||||
assertTrue { abs(abs(res.mutableBuffer.array()[res.bufferStart + 1]) - 0.922) < 0.01 }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSVD() = DoubleTensorAlgebra{
|
||||
testSVDFor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)))
|
||||
testSVDFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBatchedSVD() = DoubleTensorAlgebra {
|
||||
val tensor = randomNormal(intArrayOf(2, 5, 3), 0)
|
||||
val (tensorU, tensorS, tensorV) = tensor.svd()
|
||||
val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose())
|
||||
assertTrue(tensor.eq(tensorSVD))
|
||||
assertTrue { abs(abs(resBuffer[resStart]) - 0.386) < 0.01 }
|
||||
assertTrue { abs(abs(resBuffer[resStart + 1]) - 0.922) < 0.01 }
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -184,13 +173,118 @@ internal class TestDoubleLinearOpsTensorAlgebra {
|
||||
assertTrue(tensorSigma.eq(tensorSigmaCalc))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSVD() = DoubleTensorAlgebra{
|
||||
testSVDFor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)))
|
||||
testSVDFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0)))
|
||||
val buffer1 = doubleArrayOf(
|
||||
1.000000, 2.000000, 3.000000,
|
||||
2.000000, 3.000000, 4.000000,
|
||||
3.000000, 4.000000, 5.000000,
|
||||
4.000000, 5.000000, 6.000000,
|
||||
5.000000, 6.000000, 9.000000
|
||||
)
|
||||
testSVDFor(fromArray(intArrayOf(5, 3), buffer1))
|
||||
val buffer2 = doubleArrayOf(
|
||||
1.0, 2.0, 3.0, 2.0, 3.0,
|
||||
4.0, 3.0, 4.0, 5.0, 4.0,
|
||||
5.0, 6.0, 5.0, 6.0, 7.0
|
||||
)
|
||||
testSVDFor(fromArray(intArrayOf(3, 5), buffer2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBatchedSVD() = DoubleTensorAlgebra{
|
||||
val tensor1 = randomNormal(intArrayOf(2, 5, 3), 0)
|
||||
testSVDFor(tensor1)
|
||||
val tensor2 = DoubleTensorAlgebra.randomNormal(intArrayOf(30, 30, 30), 0)
|
||||
testSVDFor(tensor2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSVDGolubKahan() = DoubleTensorAlgebra{
|
||||
testSVDGolubKahanFor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)))
|
||||
testSVDGolubKahanFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0)))
|
||||
val buffer1 = doubleArrayOf(
|
||||
1.000000, 2.000000, 3.000000,
|
||||
2.000000, 3.000000, 4.000000,
|
||||
3.000000, 4.000000, 5.000000,
|
||||
4.000000, 5.000000, 6.000000,
|
||||
5.000000, 6.000000, 9.000000
|
||||
)
|
||||
testSVDGolubKahanFor(fromArray(intArrayOf(5, 3), buffer1))
|
||||
val buffer2 = doubleArrayOf(
|
||||
1.0, 2.0, 3.0, 2.0, 3.0,
|
||||
4.0, 3.0, 4.0, 5.0, 4.0,
|
||||
5.0, 6.0, 5.0, 6.0, 7.0
|
||||
)
|
||||
testSVDGolubKahanFor(fromArray(intArrayOf(3, 5), buffer2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBatchedSVDGolubKahan() = DoubleTensorAlgebra{
|
||||
val tensor1 = randomNormal(intArrayOf(2, 5, 3), 0)
|
||||
testSVDGolubKahanFor(tensor1)
|
||||
val tensor2 = DoubleTensorAlgebra.randomNormal(intArrayOf(30, 30, 30), 0)
|
||||
testSVDGolubKahanFor(tensor2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSVDPowerMethod() = DoubleTensorAlgebra{
|
||||
testSVDPowerMethodFor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)))
|
||||
testSVDPowerMethodFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0)))
|
||||
val buffer1 = doubleArrayOf(
|
||||
1.000000, 2.000000, 3.000000,
|
||||
2.000000, 3.000000, 4.000000,
|
||||
3.000000, 4.000000, 5.000000,
|
||||
4.000000, 5.000000, 6.000000,
|
||||
5.000000, 6.000000, 9.000000
|
||||
)
|
||||
testSVDPowerMethodFor(fromArray(intArrayOf(5, 3), buffer1))
|
||||
val buffer2 = doubleArrayOf(
|
||||
1.0, 2.0, 3.0, 2.0, 3.0,
|
||||
4.0, 3.0, 4.0, 5.0, 4.0,
|
||||
5.0, 6.0, 5.0, 6.0, 7.0
|
||||
)
|
||||
testSVDPowerMethodFor(fromArray(intArrayOf(3, 5), buffer2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBatchedSVDPowerMethod() = DoubleTensorAlgebra {
|
||||
val tensor1 = randomNormal(intArrayOf(2, 5, 3), 0)
|
||||
testSVDPowerMethodFor(tensor1)
|
||||
val tensor2 = DoubleTensorAlgebra.randomNormal(intArrayOf(30, 30, 30), 0)
|
||||
testSVDPowerMethodFor(tensor2)
|
||||
}
|
||||
|
||||
// @Test
|
||||
// fun testSVDPowerMethodError() = DoubleTensorAlgebra{
|
||||
// val buffer = doubleArrayOf(
|
||||
// 1.000000, 2.000000, 3.000000,
|
||||
// 2.000000, 3.000000, 4.000000,
|
||||
// 3.000000, 4.000000, 5.000000,
|
||||
// 4.000000, 5.000000, 6.000000,
|
||||
// 5.000000, 6.000000, 7.000000
|
||||
// )
|
||||
// testSVDPowerMethodFor(fromArray(intArrayOf(5, 3), buffer))
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10) {
|
||||
private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor) {
|
||||
val svd = tensor.svd()
|
||||
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
|
||||
assertTrue(tensor.eq(tensorSVD))
|
||||
}
|
||||
|
||||
private fun DoubleTensorAlgebra.testSVDGolubKahanFor(tensor: DoubleTensor, epsilon: Double = 1e-10) {
|
||||
val svd = tensor.svdGolubKahan()
|
||||
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
@ -199,3 +293,15 @@ private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double
|
||||
|
||||
assertTrue(tensor.eq(tensorSVD, epsilon))
|
||||
}
|
||||
|
||||
private fun DoubleTensorAlgebra.testSVDPowerMethodFor(tensor: DoubleTensor, epsilon: Double = 1e-10) {
|
||||
val svd = tensor.svdPowerMethod()
|
||||
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
|
||||
assertTrue(tensor.eq(tensorSVD, epsilon))
|
||||
}
|
32
kmath-viktor/README.md
Normal file
32
kmath-viktor/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# 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.3.0`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-viktor:0.3.0'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-viktor:0.3.0")
|
||||
}
|
||||
```
|
@ -1,40 +1,69 @@
|
||||
public final class space/kscience/kmath/viktor/ViktorBuffer : space/kscience/kmath/structures/MutableBuffer {
|
||||
public fun <init> (Lorg/jetbrains/bio/viktor/F64FlatArray;)V
|
||||
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 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 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 class space/kscience/kmath/viktor/ViktorFieldND : space/kscience/kmath/viktor/ViktorFieldOpsND, space/kscience/kmath/nd/FieldND, space/kscience/kmath/operations/NumbersAddOps {
|
||||
public fun <init> ([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 ()[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 <init> ()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 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 atanh (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun atanh (Lspace/kscience/kmath/nd/StructureND;)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 getElementContext ()Lspace/kscience/kmath/operations/Algebra;
|
||||
public fun getElementContext ()Lspace/kscience/kmath/operations/DoubleField;
|
||||
public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra;
|
||||
public fun getElementAlgebra ()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;
|
||||
@ -43,26 +72,38 @@ public final class space/kscience/kmath/viktor/ViktorFieldND : space/kscience/km
|
||||
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 ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
|
||||
public fun structureND ([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 {
|
||||
@ -77,7 +118,6 @@ public final class space/kscience/kmath/viktor/ViktorStructureND : space/kscienc
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,6 @@
|
||||
rootProject.name = "kmath"
|
||||
|
||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||
enableFeaturePreview("VERSION_CATALOGS")
|
||||
|
||||
dependencyResolutionManagement {
|
||||
|
||||
val toolsVersion: String by extra
|
||||
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
versionCatalogs {
|
||||
create("npmlibs") {
|
||||
from("ru.mipt.npm:version-catalog:$toolsVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include(
|
||||
":kmath-memory",
|
||||
":kmath-complex",
|
||||
|
Loading…
Reference in New Issue
Block a user