diff --git a/.space.kts b/.space.kts
index 9dda0cbf7..d70ad6d59 100644
--- a/.space.kts
+++ b/.space.kts
@@ -1 +1,3 @@
-job("Build") { gradlew("openjdk:11", "build") }
+job("Build") {
+ gradlew("openjdk:11", "build")
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 214730ecc..435d958d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,13 @@
- Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140).
- Automatic README generation for features (#139)
- Native support for `memory`, `core` and `dimensions`
-- `kmath-ejml` to supply EJML SimpleMatrix wrapper.
+- `kmath-ejml` to supply EJML SimpleMatrix wrapper (https://github.com/mipt-npm/kmath/pull/136).
+- A separate `Symbol` entity, which is used for global unbound symbol.
+- A `Symbol` indexing scope.
+- Basic optimization API for Commons-math.
+- Chi squared optimization for array-like data in CM
+- `Fitting` utility object in prob/stat
+- ND4J support module submitting `NDStructure` and `NDAlgebra` over `INDArray`.
### Changed
- Package changed from `scientifik` to `kscience.kmath`.
@@ -16,6 +22,8 @@
- `Polynomial` secondary constructor made function.
- Kotlin version: 1.3.72 -> 1.4.20-M1
- `kmath-ast` doesn't depend on heavy `kotlin-reflect` library.
+- Full autodiff refactoring based on `Symbol`
+- `kmath-prob` renamed to `kmath-stat`
### Deprecated
diff --git a/README.md b/README.md
index eadc3036b..c4e3e5374 100644
--- a/README.md
+++ b/README.md
@@ -8,41 +8,50 @@ Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience
Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
# KMath
-Could be pronounced as `key-math`.
-The Kotlin MATHematics library was initially intended as a Kotlin-based analog to Python's `numpy` library. Later we found that kotlin is much more flexible language and allows superior architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could be achieved with [kmath-for-real](/kmath-for-real) extension module.
+
+Could be pronounced as `key-math`. The Kotlin MATHematics library was initially intended as a Kotlin-based analog to
+Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture
+designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could
+be achieved with [kmath-for-real](/kmath-for-real) extension module.
## Publications and talks
+
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
* [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814)
* [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103)
# Goal
-* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM and JS for now and Native in future).
+
+* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native).
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
* Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
## Non-goals
-* Be like Numpy. It was the idea at the beginning, but we decided that we can do better in terms of API.
-* Provide best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
+
+* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API.
+* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
-* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better experience for those, who want to work with specific types.
+* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
+for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better
+experience for those, who want to work with specific types.
## Features
-Actual feature list is [here](/docs/features.md)
+Current feature list is [here](/docs/features.md)
* **Algebra**
- * Algebraic structures like rings, spaces and field (**TODO** add example to wiki)
+ * Algebraic structures like rings, spaces and fields (**TODO** add example to wiki)
* Basic linear algebra operations (sums, products, etc.), backed by the `Space` API.
- * Complex numbers backed by the `Field` API (meaning that they will be usable in any structure like vectors and N-dimensional arrays).
+ * Complex numbers backed by the `Field` API (meaning they will be usable in any structure like vectors and
+ N-dimensional arrays).
* Advanced linear algebra operations like matrix inversion and LU decomposition.
* **Array-like structures** Full support of many-dimensional array-like structures
including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).
-* **Expressions** By writing a single mathematical expression
-once, users will be able to apply different types of objects to the expression by providing a context. Expressions
-can be used for a wide variety of purposes from high performance calculations to code generation.
+* **Expressions** By writing a single mathematical expression once, users will be able to apply different types of
+objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
+performance calculations to code generation.
* **Histograms** Fast multi-dimensional histograms.
@@ -50,12 +59,11 @@ can be used for a wide variety of purposes from high performance calculations to
* **Type-safe dimensions** Type-safe dimensions for matrix operations.
-* **Commons-math wrapper** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/)
- library in Kotlin code and maybe rewrite some parts to better suit the Kotlin programming paradigm, however there is no fixed roadmap for that. Feel free
- to submit a feature request if you want something to be done first.
-
-* **EJML wrapper** Provides EJML `SimpleMatrix` wrapper consistent with the core matrix structures.
-
+* **Commons-math wrapper** It is planned to gradually wrap most parts of
+[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some
+parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to
+submit a feature request if you want something to be implemented first.
+
## Planned features
* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.
@@ -101,7 +109,7 @@ can be used for a wide variety of purposes from high performance calculations to
> - [buffers](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : Functional Expressions
> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains
-> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/misc/AutoDiff.kt) : Automatic differentiation
+> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
@@ -117,6 +125,12 @@ can be used for a wide variety of purposes from high performance calculations to
> **Maturity**: EXPERIMENTAL
+* ### [kmath-ejml](kmath-ejml)
+>
+>
+> **Maturity**: EXPERIMENTAL
+
+
* ### [kmath-for-real](kmath-for-real)
>
>
@@ -147,7 +161,19 @@ can be used for a wide variety of purposes from high performance calculations to
> **Maturity**: EXPERIMENTAL
-* ### [kmath-prob](kmath-prob)
+* ### [kmath-nd4j](kmath-nd4j)
+> ND4J NDStructure implementation and according NDAlgebra classes
+>
+> **Maturity**: EXPERIMENTAL
+>
+> **Features:**
+> - [nd4jarraystrucure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray
+> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long
+> - [nd4jarrayfields](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : Fields over Nd4jArrayStructure of Float and Double
+
+
+
+* ### [kmath-stat](kmath-stat)
>
>
> **Maturity**: EXPERIMENTAL
@@ -162,39 +188,69 @@ can be used for a wide variety of purposes from high performance calculations to
## Multi-platform support
-KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the [common module](/kmath-core/src/commonMain). Implementation is also done in the common module wherever possible. In some cases, features are delegated to platform-specific implementations even if they could be done in the common module for performance reasons. Currently, the JVM is the main focus of development, however Kotlin/Native and Kotlin/JS contributions are also welcome.
+KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the
+[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features
+are delegated to platform-specific implementations even if they could be provided in the common module for performance
+reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and
+feedback are also welcome.
## Performance
-Calculation performance is one of major goals of KMath in the future, but in some cases it is not possible to achieve both performance and flexibility. We expect to focus on creating convenient universal API first and then work on increasing performance for specific cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy.
+Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve
+both performance and flexibility.
-### Dependency
+We expect to focus on creating convenient universal API first and then work on increasing performance for specific
+cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized
+native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
+better than SciPy.
-Release artifacts are accessible from bintray with following configuration (see documentation for [kotlin-multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) form more details):
+### Repositories
+
+Release artifacts are accessible from bintray with following configuration (see documentation of
+[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details):
```kotlin
-repositories{
+repositories {
+ jcenter()
+ maven("https://clojars.org/repo")
+ maven("https://dl.bintray.com/egor-bogomolov/astminer/")
+ maven("https://dl.bintray.com/hotkeytlt/maven")
+ maven("https://dl.bintray.com/kotlin/kotlin-eap")
+ maven("https://dl.bintray.com/kotlin/kotlinx")
maven("https://dl.bintray.com/mipt-npm/kscience")
+ maven("https://jitpack.io")
+ mavenCentral()
}
-dependencies{
- api("kscience.kmath:kmath-core:${kmathVersion}")
- //api("scientifik:kmath-core:${kmathVersion}") for 0.1.3 and earlier
+dependencies {
+ api("kscience.kmath:kmath-core:0.2.0-dev-3")
+ // api("kscience.kmath:kmath-core-jvm:0.2.0-dev-3") for jvm-specific version
}
```
Gradle `6.0+` is required for multiplatform artifacts.
-### Development
+#### Development
+
+Development builds are uploaded to the separate repository:
-Development builds are accessible from the reposirtory
```kotlin
-repositories{
+repositories {
+ jcenter()
+ maven("https://clojars.org/repo")
+ maven("https://dl.bintray.com/egor-bogomolov/astminer/")
+ maven("https://dl.bintray.com/hotkeytlt/maven")
+ maven("https://dl.bintray.com/kotlin/kotlin-eap")
+ maven("https://dl.bintray.com/kotlin/kotlinx")
maven("https://dl.bintray.com/mipt-npm/dev")
+ maven("https://jitpack.io")
+ mavenCentral()
}
```
-with the same artifact names.
## Contributing
-The project requires a lot of additional work. Please feel free to contribute in any way and propose new features.
+The project requires a lot of additional work. The most important thing we need is a feedback about what features are
+required the most. Feel free to create feature requests. We are also welcome to code contributions,
+especially in issues marked with
+[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label.
diff --git a/build.gradle.kts b/build.gradle.kts
index 05e2d5979..3514c91e6 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,17 +1,26 @@
+import ru.mipt.npm.gradle.KSciencePublishPlugin
+
plugins {
id("ru.mipt.npm.project")
}
-val kmathVersion: String by extra("0.2.0-dev-2")
-val bintrayRepo: String by extra("kscience")
-val githubProject: String by extra("kmath")
+internal val kmathVersion: String by extra("0.2.0-dev-3")
+internal val bintrayRepo: String by extra("kscience")
+internal val githubProject: String by extra("kmath")
allprojects {
repositories {
jcenter()
+ maven("https://clojars.org/repo")
+ maven("https://dl.bintray.com/egor-bogomolov/astminer/")
+ maven("https://dl.bintray.com/hotkeytlt/maven")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/kotlin/kotlinx")
- maven("https://dl.bintray.com/hotkeytlt/maven")
+ maven("https://dl.bintray.com/mipt-npm/dev")
+ maven("https://dl.bintray.com/mipt-npm/kscience")
+ maven("https://jitpack.io")
+ maven("http://logicrunch.research.it.uu.se/maven/")
+ mavenCentral()
}
group = "kscience.kmath"
@@ -19,9 +28,13 @@ allprojects {
}
subprojects {
- if (name.startsWith("kmath")) apply()
+ if (name.startsWith("kmath")) apply()
}
readme {
readmeTemplate = file("docs/templates/README-TEMPLATE.md")
}
+
+apiValidation {
+ validationDisabled = true
+}
diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md
index f451adb24..ee1df818c 100644
--- a/docs/templates/README-TEMPLATE.md
+++ b/docs/templates/README-TEMPLATE.md
@@ -8,41 +8,50 @@ Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience
Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
# KMath
-Could be pronounced as `key-math`.
-The Kotlin MATHematics library was initially intended as a Kotlin-based analog to Python's `numpy` library. Later we found that kotlin is much more flexible language and allows superior architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could be achieved with [kmath-for-real](/kmath-for-real) extension module.
+
+Could be pronounced as `key-math`. The Kotlin MATHematics library was initially intended as a Kotlin-based analog to
+Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture
+designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could
+be achieved with [kmath-for-real](/kmath-for-real) extension module.
## Publications and talks
+
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
* [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814)
* [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103)
# Goal
-* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM and JS for now and Native in future).
+
+* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native).
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
* Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
## Non-goals
-* Be like Numpy. It was the idea at the beginning, but we decided that we can do better in terms of API.
-* Provide best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
+
+* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API.
+* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
-* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better experience for those, who want to work with specific types.
+* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
+for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better
+experience for those, who want to work with specific types.
## Features
-Actual feature list is [here](/docs/features.md)
+Current feature list is [here](/docs/features.md)
* **Algebra**
- * Algebraic structures like rings, spaces and field (**TODO** add example to wiki)
+ * Algebraic structures like rings, spaces and fields (**TODO** add example to wiki)
* Basic linear algebra operations (sums, products, etc.), backed by the `Space` API.
- * Complex numbers backed by the `Field` API (meaning that they will be usable in any structure like vectors and N-dimensional arrays).
+ * Complex numbers backed by the `Field` API (meaning they will be usable in any structure like vectors and
+ N-dimensional arrays).
* Advanced linear algebra operations like matrix inversion and LU decomposition.
* **Array-like structures** Full support of many-dimensional array-like structures
including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).
-* **Expressions** By writing a single mathematical expression
-once, users will be able to apply different types of objects to the expression by providing a context. Expressions
-can be used for a wide variety of purposes from high performance calculations to code generation.
+* **Expressions** By writing a single mathematical expression once, users will be able to apply different types of
+objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
+performance calculations to code generation.
* **Histograms** Fast multi-dimensional histograms.
@@ -50,9 +59,10 @@ can be used for a wide variety of purposes from high performance calculations to
* **Type-safe dimensions** Type-safe dimensions for matrix operations.
-* **Commons-math wrapper** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/)
- library in Kotlin code and maybe rewrite some parts to better suit the Kotlin programming paradigm, however there is no fixed roadmap for that. Feel free
- to submit a feature request if you want something to be done first.
+* **Commons-math wrapper** It is planned to gradually wrap most parts of
+[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some
+parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to
+submit a feature request if you want something to be implemented first.
## Planned features
@@ -72,39 +82,53 @@ $modules
## Multi-platform support
-KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the [common module](/kmath-core/src/commonMain). Implementation is also done in the common module wherever possible. In some cases, features are delegated to platform-specific implementations even if they could be done in the common module for performance reasons. Currently, the JVM is the main focus of development, however Kotlin/Native and Kotlin/JS contributions are also welcome.
+KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the
+[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features
+are delegated to platform-specific implementations even if they could be provided in the common module for performance
+reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and
+feedback are also welcome.
## Performance
-Calculation performance is one of major goals of KMath in the future, but in some cases it is not possible to achieve both performance and flexibility. We expect to focus on creating convenient universal API first and then work on increasing performance for specific cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy.
+Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve
+both performance and flexibility.
-### Dependency
+We expect to focus on creating convenient universal API first and then work on increasing performance for specific
+cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized
+native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
+better than SciPy.
-Release artifacts are accessible from bintray with following configuration (see documentation for [kotlin-multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) form more details):
+### Repositories
+
+Release artifacts are accessible from bintray with following configuration (see documentation of
+[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details):
```kotlin
-repositories{
+repositories {
maven("https://dl.bintray.com/mipt-npm/kscience")
}
-dependencies{
+dependencies {
api("kscience.kmath:kmath-core:$version")
- //api("kscience.kmath:kmath-core-jvm:$version") for jvm-specific version
+ // api("kscience.kmath:kmath-core-jvm:$version") for jvm-specific version
}
```
Gradle `6.0+` is required for multiplatform artifacts.
-### Development
+#### Development
+
+Development builds are uploaded to the separate repository:
-Development builds are accessible from the reposirtory
```kotlin
-repositories{
+repositories {
maven("https://dl.bintray.com/mipt-npm/dev")
}
```
-with the same artifact names.
## Contributing
-The project requires a lot of additional work. Please feel free to contribute in any way and propose new features.
+The project requires a lot of additional work. The most important thing we need is a feedback about what features are
+required the most. Feel free to create feature requests. We are also welcome to code contributions,
+especially in issues marked with
+[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label.
diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts
index 900da966b..d42627ff0 100644
--- a/examples/build.gradle.kts
+++ b/examples/build.gradle.kts
@@ -8,25 +8,46 @@ plugins {
}
allOpen.annotation("org.openjdk.jmh.annotations.State")
+sourceSets.register("benchmarks")
repositories {
- maven("https://dl.bintray.com/mipt-npm/kscience")
+ jcenter()
+ maven("https://clojars.org/repo")
+ maven("https://dl.bintray.com/egor-bogomolov/astminer/")
+ maven("https://dl.bintray.com/hotkeytlt/maven")
+ maven("https://dl.bintray.com/kotlin/kotlin-eap")
+ maven("https://dl.bintray.com/kotlin/kotlinx")
maven("https://dl.bintray.com/mipt-npm/dev")
- maven("https://dl.bintray.com/kotlin/kotlin-dev/")
+ maven("https://dl.bintray.com/mipt-npm/kscience")
+ maven("https://jitpack.io")
+ maven("http://logicrunch.research.it.uu.se/maven/")
mavenCentral()
}
-sourceSets.register("benchmarks")
-
dependencies {
-// implementation(project(":kmath-ast"))
+ implementation(project(":kmath-ast"))
+ implementation(project(":kmath-kotlingrad"))
implementation(project(":kmath-core"))
implementation(project(":kmath-coroutines"))
implementation(project(":kmath-commons"))
- implementation(project(":kmath-prob"))
+ implementation(project(":kmath-stat"))
implementation(project(":kmath-viktor"))
implementation(project(":kmath-dimensions"))
implementation(project(":kmath-ejml"))
+ implementation(project(":kmath-nd4j"))
+ implementation("org.deeplearning4j:deeplearning4j-core:1.0.0-beta7")
+ implementation("org.nd4j:nd4j-native:1.0.0-beta7")
+
+// uncomment if your system supports AVX2
+// val os = System.getProperty("os.name")
+//
+// if (System.getProperty("os.arch") in arrayOf("x86_64", "amd64")) when {
+// os.startsWith("Windows") -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:windows-x86_64-avx2")
+// os == "Linux" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:linux-x86_64-avx2")
+// os == "Mac OS X" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:macosx-x86_64-avx2")
+// } else
+ implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
+
implementation("org.jetbrains.kotlinx:kotlinx-io:0.2.0-npm-dev-11")
implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20")
implementation("org.slf4j:slf4j-simple:1.7.30")
@@ -55,4 +76,6 @@ kotlin.sourceSets.all {
}
}
-tasks.withType { kotlinOptions.jvmTarget = "11" }
+tasks.withType {
+ kotlinOptions.jvmTarget = "11"
+}
diff --git a/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt b/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt
index f0a32e5bd..a4806ed68 100644
--- a/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt
+++ b/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt
@@ -1,70 +1,80 @@
package kscience.kmath.ast
-//
-//import kscience.kmath.asm.compile
-//import kscience.kmath.expressions.Expression
-//import kscience.kmath.expressions.expressionInField
-//import kscience.kmath.expressions.invoke
-//import kscience.kmath.operations.Field
-//import kscience.kmath.operations.RealField
-//import kotlin.random.Random
-//import kotlin.system.measureTimeMillis
-//
-//class ExpressionsInterpretersBenchmark {
-// private val algebra: Field = RealField
-// fun functionalExpression() {
-// val expr = algebra.expressionInField {
-// variable("x") * const(2.0) + const(2.0) / variable("x") - const(16.0)
-// }
-//
-// invokeAndSum(expr)
-// }
-//
-// fun mstExpression() {
-// val expr = algebra.mstInField {
-// symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
-// }
-//
-// invokeAndSum(expr)
-// }
-//
-// fun asmExpression() {
-// val expr = algebra.mstInField {
-// symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
-// }.compile()
-//
-// invokeAndSum(expr)
-// }
-//
-// private fun invokeAndSum(expr: Expression) {
-// val random = Random(0)
-// var sum = 0.0
-//
-// repeat(1000000) {
-// sum += expr("x" to random.nextDouble())
-// }
-//
-// println(sum)
-// }
-//}
-//
-//fun main() {
-// val benchmark = ExpressionsInterpretersBenchmark()
-//
-// val fe = measureTimeMillis {
-// benchmark.functionalExpression()
-// }
-//
-// println("fe=$fe")
-//
-// val mst = measureTimeMillis {
-// benchmark.mstExpression()
-// }
-//
-// println("mst=$mst")
-//
-// val asm = measureTimeMillis {
-// benchmark.asmExpression()
-// }
-//
-// println("asm=$asm")
-//}
+
+import kscience.kmath.asm.compile
+import kscience.kmath.expressions.Expression
+import kscience.kmath.expressions.expressionInField
+import kscience.kmath.expressions.invoke
+import kscience.kmath.operations.Field
+import kscience.kmath.operations.RealField
+import kotlin.random.Random
+import kotlin.system.measureTimeMillis
+
+internal class ExpressionsInterpretersBenchmark {
+ private val algebra: Field = RealField
+ fun functionalExpression() {
+ val expr = algebra.expressionInField {
+ symbol("x") * const(2.0) + const(2.0) / symbol("x") - const(16.0)
+ }
+
+ invokeAndSum(expr)
+ }
+
+ fun mstExpression() {
+ val expr = algebra.mstInField {
+ symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
+ }
+
+ invokeAndSum(expr)
+ }
+
+ fun asmExpression() {
+ val expr = algebra.mstInField {
+ symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
+ }.compile()
+
+ invokeAndSum(expr)
+ }
+
+ private fun invokeAndSum(expr: Expression) {
+ val random = Random(0)
+ var sum = 0.0
+
+ repeat(1000000) {
+ sum += expr("x" to random.nextDouble())
+ }
+
+ println(sum)
+ }
+}
+
+/**
+ * This benchmark compares basically evaluation of simple function with MstExpression interpreter, ASM backend and
+ * core FunctionalExpressions API.
+ *
+ * The expected rating is:
+ *
+ * 1. ASM.
+ * 2. MST.
+ * 3. FE.
+ */
+fun main() {
+ val benchmark = ExpressionsInterpretersBenchmark()
+
+ val fe = measureTimeMillis {
+ benchmark.functionalExpression()
+ }
+
+ println("fe=$fe")
+
+ val mst = measureTimeMillis {
+ benchmark.mstExpression()
+ }
+
+ println("mst=$mst")
+
+ val asm = measureTimeMillis {
+ benchmark.asmExpression()
+ }
+
+ println("asm=$asm")
+}
diff --git a/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt b/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt
new file mode 100644
index 000000000..b3c827503
--- /dev/null
+++ b/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt
@@ -0,0 +1,24 @@
+package kscience.kmath.ast
+
+import kscience.kmath.asm.compile
+import kscience.kmath.expressions.derivative
+import kscience.kmath.expressions.invoke
+import kscience.kmath.expressions.symbol
+import kscience.kmath.kotlingrad.differentiable
+import kscience.kmath.operations.RealField
+
+/**
+ * In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
+ * valid derivative.
+ */
+fun main() {
+ val x by symbol
+
+ val actualDerivative = MstExpression(RealField, "x^2-4*x-44".parseMath())
+ .differentiable()
+ .derivative(x)
+ .compile()
+
+ val expectedDerivative = MstExpression(RealField, "2*x-4".parseMath()).compile()
+ assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
+}
diff --git a/examples/src/main/kotlin/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/kscience/kmath/operations/ComplexDemo.kt
index 34b3c9981..e84fd8df3 100644
--- a/examples/src/main/kotlin/kscience/kmath/operations/ComplexDemo.kt
+++ b/examples/src/main/kotlin/kscience/kmath/operations/ComplexDemo.kt
@@ -6,8 +6,8 @@ import kscience.kmath.structures.complex
fun main() {
// 2d element
- val element = NDElement.complex(2, 2) { index: IntArray ->
- Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble())
+ val element = NDElement.complex(2, 2) { (i,j) ->
+ Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
}
println(element)
diff --git a/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt
index 28bfab779..e53af0dee 100644
--- a/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt
+++ b/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt
@@ -1,8 +1,10 @@
package kscience.kmath.structures
import kotlinx.coroutines.GlobalScope
+import kscience.kmath.nd4j.Nd4jArrayField
import kscience.kmath.operations.RealField
import kscience.kmath.operations.invoke
+import org.nd4j.linalg.factory.Nd4j
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.system.measureTimeMillis
@@ -14,6 +16,8 @@ internal inline fun measureAndPrint(title: String, block: () -> Unit) {
}
fun main() {
+ // initializing Nd4j
+ Nd4j.zeros(0)
val dim = 1000
val n = 1000
@@ -23,6 +27,8 @@ fun main() {
val specializedField = NDField.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives.
val genericField = NDField.boxing(RealField, dim, dim)
+ // Nd4j specialized field.
+ val nd4jField = Nd4jArrayField.real(dim, dim)
measureAndPrint("Automatic field addition") {
autoField {
@@ -43,6 +49,13 @@ fun main() {
}
}
+ measureAndPrint("Nd4j specialized addition") {
+ nd4jField {
+ var res = one
+ repeat(n) { res += 1.0 as Number }
+ }
+ }
+
measureAndPrint("Lazy addition") {
val res = specializedField.one.mapAsync(GlobalScope) {
var c = 0.0
diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt
index 64a820b20..6ee6ab9af 100644
--- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt
+++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt
@@ -6,14 +6,14 @@ import kscience.kmath.operations.*
* [Algebra] over [MST] nodes.
*/
public object MstAlgebra : NumericAlgebra {
- override fun number(value: Number): MST = MST.Numeric(value)
+ override fun number(value: Number): MST.Numeric = MST.Numeric(value)
- override fun symbol(value: String): MST = MST.Symbolic(value)
+ override fun symbol(value: String): MST.Symbolic = MST.Symbolic(value)
- override fun unaryOperation(operation: String, arg: MST): MST =
+ override fun unaryOperation(operation: String, arg: MST): MST.Unary =
MST.Unary(operation, arg)
- override fun binaryOperation(operation: String, left: MST, right: MST): MST =
+ override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
MST.Binary(operation, left, right)
}
@@ -21,97 +21,100 @@ public object MstAlgebra : NumericAlgebra {
* [Space] over [MST] nodes.
*/
public object MstSpace : Space, NumericAlgebra {
- override val zero: MST = number(0.0)
+ override val zero: MST.Numeric by lazy { number(0.0) }
- override fun number(value: Number): MST = MstAlgebra.number(value)
- override fun symbol(value: String): MST = MstAlgebra.symbol(value)
- override fun add(a: MST, b: MST): MST = binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
- override fun multiply(a: MST, k: Number): MST = binaryOperation(RingOperations.TIMES_OPERATION, a, number(k))
+ override fun number(value: Number): MST.Numeric = MstAlgebra.number(value)
+ override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value)
+ override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
+ override fun multiply(a: MST, k: Number): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION, a, number(k))
- override fun binaryOperation(operation: String, left: MST, right: MST): MST =
+ override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
MstAlgebra.binaryOperation(operation, left, right)
- override fun unaryOperation(operation: String, arg: MST): MST = MstAlgebra.unaryOperation(operation, arg)
+ override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstAlgebra.unaryOperation(operation, arg)
}
/**
* [Ring] over [MST] nodes.
*/
public object MstRing : Ring, NumericAlgebra {
- override val zero: MST
+ override val zero: MST.Numeric
get() = MstSpace.zero
- override val one: MST = number(1.0)
- override fun number(value: Number): MST = MstSpace.number(value)
- override fun symbol(value: String): MST = MstSpace.symbol(value)
- override fun add(a: MST, b: MST): MST = MstSpace.add(a, b)
+ override val one: MST.Numeric by lazy { number(1.0) }
- override fun multiply(a: MST, k: Number): MST = MstSpace.multiply(a, k)
+ override fun number(value: Number): MST.Numeric = MstSpace.number(value)
+ override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value)
+ override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b)
+ override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k)
+ override fun multiply(a: MST, b: MST): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION, a, b)
- override fun multiply(a: MST, b: MST): MST = binaryOperation(RingOperations.TIMES_OPERATION, a, b)
-
- override fun binaryOperation(operation: String, left: MST, right: MST): MST =
+ override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
MstSpace.binaryOperation(operation, left, right)
- override fun unaryOperation(operation: String, arg: MST): MST = MstAlgebra.unaryOperation(operation, arg)
+ override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstSpace.unaryOperation(operation, arg)
}
/**
* [Field] over [MST] nodes.
*/
public object MstField : Field {
- public override val zero: MST
+ public override val zero: MST.Numeric
get() = MstRing.zero
- public override val one: MST
+ public override val one: MST.Numeric
get() = MstRing.one
- public override fun symbol(value: String): MST = MstRing.symbol(value)
- public override fun number(value: Number): MST = MstRing.number(value)
- public override fun add(a: MST, b: MST): MST = MstRing.add(a, b)
- public override fun multiply(a: MST, k: Number): MST = MstRing.multiply(a, k)
- public override fun multiply(a: MST, b: MST): MST = MstRing.multiply(a, b)
- public override fun divide(a: MST, b: MST): MST = binaryOperation(FieldOperations.DIV_OPERATION, a, b)
+ public override fun symbol(value: String): MST.Symbolic = MstRing.symbol(value)
+ public override fun number(value: Number): MST.Numeric = MstRing.number(value)
+ public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b)
+ public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k)
+ public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b)
+ public override fun divide(a: MST, b: MST): MST.Binary = binaryOperation(FieldOperations.DIV_OPERATION, a, b)
- public override fun binaryOperation(operation: String, left: MST, right: MST): MST =
+ public override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
MstRing.binaryOperation(operation, left, right)
- override fun unaryOperation(operation: String, arg: MST): MST = MstRing.unaryOperation(operation, arg)
+ override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstRing.unaryOperation(operation, arg)
}
/**
* [ExtendedField] over [MST] nodes.
*/
public object MstExtendedField : ExtendedField {
- override val zero: MST
+ override val zero: MST.Numeric
get() = MstField.zero
- override val one: MST
+ override val one: MST.Numeric
get() = MstField.one
- override fun symbol(value: String): MST = MstField.symbol(value)
- override fun sin(arg: MST): MST = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg)
- override fun cos(arg: MST): MST = unaryOperation(TrigonometricOperations.COS_OPERATION, arg)
- override fun tan(arg: MST): MST = unaryOperation(TrigonometricOperations.TAN_OPERATION, arg)
- override fun asin(arg: MST): MST = unaryOperation(TrigonometricOperations.ASIN_OPERATION, arg)
- override fun acos(arg: MST): MST = unaryOperation(TrigonometricOperations.ACOS_OPERATION, arg)
- override fun atan(arg: MST): MST = unaryOperation(TrigonometricOperations.ATAN_OPERATION, arg)
- override fun sinh(arg: MST): MST = unaryOperation(HyperbolicOperations.SINH_OPERATION, arg)
- override fun cosh(arg: MST): MST = unaryOperation(HyperbolicOperations.COSH_OPERATION, arg)
- override fun tanh(arg: MST): MST = unaryOperation(HyperbolicOperations.TANH_OPERATION, arg)
- override fun asinh(arg: MST): MST = unaryOperation(HyperbolicOperations.ASINH_OPERATION, arg)
- override fun acosh(arg: MST): MST = unaryOperation(HyperbolicOperations.ACOSH_OPERATION, arg)
- override fun atanh(arg: MST): MST = unaryOperation(HyperbolicOperations.ATANH_OPERATION, arg)
- override fun add(a: MST, b: MST): MST = MstField.add(a, b)
- override fun multiply(a: MST, k: Number): MST = MstField.multiply(a, k)
- override fun multiply(a: MST, b: MST): MST = MstField.multiply(a, b)
- override fun divide(a: MST, b: MST): MST = MstField.divide(a, b)
- override fun power(arg: MST, pow: Number): MST = binaryOperation(PowerOperations.POW_OPERATION, arg, number(pow))
- override fun exp(arg: MST): MST = unaryOperation(ExponentialOperations.EXP_OPERATION, arg)
- override fun ln(arg: MST): MST = unaryOperation(ExponentialOperations.LN_OPERATION, arg)
+ override fun symbol(value: String): MST.Symbolic = MstField.symbol(value)
+ override fun number(value: Number): MST.Numeric = MstField.number(value)
+ override fun sin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg)
+ override fun cos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.COS_OPERATION, arg)
+ override fun tan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.TAN_OPERATION, arg)
+ override fun asin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ASIN_OPERATION, arg)
+ override fun acos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ACOS_OPERATION, arg)
+ override fun atan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ATAN_OPERATION, arg)
+ override fun sinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.SINH_OPERATION, arg)
+ override fun cosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.COSH_OPERATION, arg)
+ override fun tanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.TANH_OPERATION, arg)
+ override fun asinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ASINH_OPERATION, arg)
+ override fun acosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ACOSH_OPERATION, arg)
+ override fun atanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ATANH_OPERATION, arg)
+ override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b)
+ override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k)
+ override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b)
+ override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b)
- override fun binaryOperation(operation: String, left: MST, right: MST): MST =
+ override fun power(arg: MST, pow: Number): MST.Binary =
+ binaryOperation(PowerOperations.POW_OPERATION, arg, number(pow))
+
+ override fun exp(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.EXP_OPERATION, arg)
+ override fun ln(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.LN_OPERATION, arg)
+
+ override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
MstField.binaryOperation(operation, left, right)
- override fun unaryOperation(operation: String, arg: MST): MST = MstField.unaryOperation(operation, arg)
+ override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstField.unaryOperation(operation, arg)
}
diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt
index 483bc530c..f68e3f5f8 100644
--- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt
+++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt
@@ -13,21 +13,22 @@ import kotlin.contracts.contract
* @property mst the [MST] node.
* @author Alexander Nozik
*/
-public class MstExpression(public val algebra: Algebra, public val mst: MST) : Expression {
- private inner class InnerAlgebra(val arguments: Map) : NumericAlgebra {
- override fun symbol(value: String): T = arguments[value] ?: algebra.symbol(value)
+public class MstExpression>(public val algebra: A, public val mst: MST) : Expression {
+ private inner class InnerAlgebra(val arguments: Map) : NumericAlgebra {
+ override fun symbol(value: String): T = arguments[StringSymbol(value)] ?: algebra.symbol(value)
override fun unaryOperation(operation: String, arg: T): T = algebra.unaryOperation(operation, arg)
override fun binaryOperation(operation: String, left: T, right: T): T =
algebra.binaryOperation(operation, left, right)
- override fun number(value: Number): T = if (algebra is NumericAlgebra)
- algebra.number(value)
+ @Suppress("UNCHECKED_CAST")
+ override fun number(value: Number): T = if (algebra is NumericAlgebra<*>)
+ (algebra as NumericAlgebra).number(value)
else
error("Numeric nodes are not supported by $this")
}
- override operator fun invoke(arguments: Map): T = InnerAlgebra(arguments).evaluate(mst)
+ override operator fun invoke(arguments: Map): T = InnerAlgebra(arguments).evaluate(mst)
}
/**
@@ -37,15 +38,15 @@ public class MstExpression(public val algebra: Algebra, public val mst: MS
*/
public inline fun , E : Algebra> A.mst(
mstAlgebra: E,
- block: E.() -> MST
-): MstExpression = MstExpression(this, mstAlgebra.block())
+ block: E.() -> MST,
+): MstExpression = MstExpression(this, mstAlgebra.block())
/**
* Builds [MstExpression] over [Space].
*
* @author Alexander Nozik
*/
-public inline fun Space.mstInSpace(block: MstSpace.() -> MST): MstExpression {
+public inline fun > A.mstInSpace(block: MstSpace.() -> MST): MstExpression {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return MstExpression(this, MstSpace.block())
}
@@ -55,7 +56,7 @@ public inline fun Space.mstInSpace(block: MstSpace.() -> MS
*
* @author Alexander Nozik
*/
-public inline fun Ring.mstInRing(block: MstRing.() -> MST): MstExpression {
+public inline fun > A.mstInRing(block: MstRing.() -> MST): MstExpression {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return MstExpression(this, MstRing.block())
}
@@ -65,7 +66,7 @@ public inline fun Ring.mstInRing(block: MstRing.() -> MST):
*
* @author Alexander Nozik
*/
-public inline fun Field.mstInField(block: MstField.() -> MST): MstExpression {
+public inline fun > A.mstInField(block: MstField.() -> MST): MstExpression {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return MstExpression(this, MstField.block())
}
@@ -75,7 +76,7 @@ public inline fun Field.mstInField(block: MstField.() -> MS
*
* @author Iaroslav Postovalov
*/
-public inline fun Field.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression {
+public inline fun > A.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return MstExpression(this, MstExtendedField.block())
}
@@ -85,7 +86,7 @@ public inline fun Field.mstInExtendedField(block: MstExtend
*
* @author Alexander Nozik
*/
-public inline fun > FunctionalExpressionSpace.mstInSpace(block: MstSpace.() -> MST): MstExpression {
+public inline fun > FunctionalExpressionSpace.mstInSpace(block: MstSpace.() -> MST): MstExpression {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return algebra.mstInSpace(block)
}
@@ -95,7 +96,7 @@ public inline fun > FunctionalExpressionSpace> FunctionalExpressionRing.mstInRing(block: MstRing.() -> MST): MstExpression {
+public inline fun > FunctionalExpressionRing.mstInRing(block: MstRing.() -> MST): MstExpression {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return algebra.mstInRing(block)
}
@@ -105,7 +106,7 @@ public inline fun > FunctionalExpressionRing.
*
* @author Alexander Nozik
*/
-public inline fun > FunctionalExpressionField.mstInField(block: MstField.() -> MST): MstExpression {
+public inline fun > FunctionalExpressionField.mstInField(block: MstField.() -> MST): MstExpression {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return algebra.mstInField(block)
}
@@ -116,8 +117,8 @@ public inline fun > FunctionalExpressionField> FunctionalExpressionExtendedField.mstInExtendedField(
- block: MstExtendedField.() -> MST
-): MstExpression {
+ block: MstExtendedField.() -> MST,
+): MstExpression {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return algebra.mstInExtendedField(block)
}
diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt
index 2b6fa6247..9ccfa464c 100644
--- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt
+++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt
@@ -69,4 +69,5 @@ public inline fun Algebra.expression(mst: MST): Expression<
*
* @author Alexander Nozik.
*/
-public inline fun MstExpression.compile(): Expression = mst.compileWith(T::class.java, algebra)
+public inline fun MstExpression>.compile(): Expression =
+ mst.compileWith(T::class.java, algebra)
diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt
index 06f02a94d..a1e482103 100644
--- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt
+++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt
@@ -25,7 +25,7 @@ internal class AsmBuilder internal constructor(
private val classOfT: Class<*>,
private val algebra: Algebra,
private val className: String,
- private val invokeLabel0Visitor: AsmBuilder.() -> Unit
+ private val invokeLabel0Visitor: AsmBuilder.() -> Unit,
) {
/**
* Internal classloader of [AsmBuilder] with alias to define class from byte array.
@@ -379,22 +379,14 @@ internal class AsmBuilder internal constructor(
* Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The [defaultValue] may be
* provided.
*/
- internal fun loadVariable(name: String, defaultValue: T? = null): Unit = invokeMethodVisitor.run {
+ internal fun loadVariable(name: String): Unit = invokeMethodVisitor.run {
load(invokeArgumentsVar, MAP_TYPE)
aconst(name)
- if (defaultValue != null)
- loadTConstant(defaultValue)
-
invokestatic(
MAP_INTRINSICS_TYPE.internalName,
"getOrFail",
-
- Type.getMethodDescriptor(
- OBJECT_TYPE,
- MAP_TYPE,
- OBJECT_TYPE,
- *OBJECT_TYPE.wrapToArrayIf { defaultValue != null }),
+ Type.getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE),
false
)
@@ -429,7 +421,7 @@ internal class AsmBuilder internal constructor(
method: String,
descriptor: String,
expectedArity: Int,
- opcode: Int = INVOKEINTERFACE
+ opcode: Int = INVOKEINTERFACE,
) {
run loop@{
repeat(expectedArity) {
diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/mapIntrinsics.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/mapIntrinsics.kt
index 708b3c2b4..588b9611a 100644
--- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/mapIntrinsics.kt
+++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/mapIntrinsics.kt
@@ -2,11 +2,12 @@
package kscience.kmath.asm.internal
+import kscience.kmath.expressions.StringSymbol
+import kscience.kmath.expressions.Symbol
+
/**
- * Gets value with given [key] or throws [IllegalStateException] whenever it is not present.
+ * Gets value with given [key] or throws [NoSuchElementException] whenever it is not present.
*
* @author Iaroslav Postovalov
*/
-@JvmOverloads
-internal fun Map.getOrFail(key: K, default: V? = null): V =
- this[key] ?: default ?: error("Parameter not found: $key")
+internal fun Map.getOrFail(key: String): V = getValue(StringSymbol(key))
diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt
index 0cf1307d1..5eebfe43d 100644
--- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt
+++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt
@@ -1,6 +1,5 @@
package kscience.kmath.asm
-import kscience.kmath.asm.compile
import kscience.kmath.ast.mstInField
import kscience.kmath.ast.mstInRing
import kscience.kmath.ast.mstInSpace
@@ -11,6 +10,7 @@ import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestAsmAlgebras {
+
@Test
fun space() {
val res1 = ByteRing.mstInSpace {
diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts
index ed6452ad8..6a44c92f2 100644
--- a/kmath-commons/build.gradle.kts
+++ b/kmath-commons/build.gradle.kts
@@ -6,7 +6,7 @@ description = "Commons math binding for kmath"
dependencies {
api(project(":kmath-core"))
api(project(":kmath-coroutines"))
- api(project(":kmath-prob"))
-// api(project(":kmath-functions"))
+ api(project(":kmath-stat"))
+ api(project(":kmath-functions"))
api("org.apache.commons:commons-math3:3.6.1")
}
diff --git a/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt
new file mode 100644
index 000000000..345babe8b
--- /dev/null
+++ b/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt
@@ -0,0 +1,121 @@
+package kscience.kmath.commons.expressions
+
+import kscience.kmath.expressions.*
+import kscience.kmath.operations.ExtendedField
+import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
+
+/**
+ * A field over commons-math [DerivativeStructure].
+ *
+ * @property order The derivation order.
+ * @property bindings The map of bindings values. All bindings are considered free parameters
+ */
+public class DerivativeStructureField(
+ public val order: Int,
+ bindings: Map,
+) : ExtendedField, ExpressionAlgebra {
+ public val numberOfVariables: Int = bindings.size
+
+ public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) }
+ public override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) }
+
+ /**
+ * A class that implements both [DerivativeStructure] and a [Symbol]
+ */
+ public inner class DerivativeStructureSymbol(
+ size: Int,
+ index: Int,
+ symbol: Symbol,
+ value: Double,
+ ) : DerivativeStructure(size, order, index, value), Symbol {
+ override val identity: String = symbol.identity
+ override fun toString(): String = identity
+ override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity
+ override fun hashCode(): Int = identity.hashCode()
+ }
+
+ /**
+ * Identity-based symbol bindings map
+ */
+ private val variables: Map = bindings.entries.mapIndexed { index, (key, value) ->
+ key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value)
+ }.toMap()
+
+ override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value)
+
+ public override fun bindOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity]
+
+ public fun bind(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity)
+
+ override fun symbol(value: String): DerivativeStructureSymbol = bind(StringSymbol(value))
+
+ public fun DerivativeStructure.derivative(symbols: List): Double {
+ require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" }
+ val ordersCount = symbols.map { it.identity }.groupBy { it }.mapValues { it.value.size }
+ return getPartialDerivative(*variables.keys.map { ordersCount[it] ?: 0 }.toIntArray())
+ }
+
+ public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList())
+
+ public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b)
+
+ public override fun multiply(a: DerivativeStructure, k: Number): DerivativeStructure = when (k) {
+ is Double -> a.multiply(k)
+ is Int -> a.multiply(k)
+ else -> a.multiply(k.toDouble())
+ }
+
+ public override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b)
+ public override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b)
+ public override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin()
+ public override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos()
+ public override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.tan()
+ public override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin()
+ public override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos()
+ public override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan()
+ public override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh()
+ public override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh()
+ public override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh()
+ public override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.asinh()
+ public override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.acosh()
+ public override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.atanh()
+
+ public override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) {
+ is Double -> arg.pow(pow)
+ is Int -> arg.pow(pow)
+ else -> arg.pow(pow.toDouble())
+ }
+
+ public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure = arg.pow(pow)
+ public override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp()
+ public override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log()
+
+ public override operator fun DerivativeStructure.plus(b: Number): DerivativeStructure = add(b.toDouble())
+ public override operator fun DerivativeStructure.minus(b: Number): DerivativeStructure = subtract(b.toDouble())
+ public override operator fun Number.plus(b: DerivativeStructure): DerivativeStructure = b + this
+ public override operator fun Number.minus(b: DerivativeStructure): DerivativeStructure = b - this
+
+ public companion object :
+ AutoDiffProcessor> {
+ public override fun process(function: DerivativeStructureField.() -> DerivativeStructure): DifferentiableExpression> =
+ DerivativeStructureExpression(function)
+ }
+}
+
+
+/**
+ * A constructs that creates a derivative structure with required order on-demand
+ */
+public class DerivativeStructureExpression(
+ public val function: DerivativeStructureField.() -> DerivativeStructure,
+) : DifferentiableExpression> {
+ public override operator fun invoke(arguments: Map): Double =
+ DerivativeStructureField(0, arguments).function().value
+
+ /**
+ * Get the derivative expression with given orders
+ */
+ public override fun derivativeOrNull(symbols: List): Expression = Expression { arguments ->
+ with(DerivativeStructureField(symbols.size, arguments)) { function().derivative(symbols) }
+ }
+}
diff --git a/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DiffExpression.kt b/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DiffExpression.kt
deleted file mode 100644
index 601675167..000000000
--- a/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DiffExpression.kt
+++ /dev/null
@@ -1,127 +0,0 @@
-package kscience.kmath.commons.expressions
-
-import kscience.kmath.expressions.Expression
-import kscience.kmath.expressions.ExpressionAlgebra
-import kscience.kmath.operations.ExtendedField
-import kscience.kmath.operations.Field
-import kscience.kmath.operations.invoke
-import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
-import kotlin.properties.ReadOnlyProperty
-
-/**
- * A field over commons-math [DerivativeStructure].
- *
- * @property order The derivation order.
- * @property parameters The map of free parameters.
- */
-public class DerivativeStructureField(
- public val order: Int,
- public val parameters: Map
-) : ExtendedField {
- public override val zero: DerivativeStructure by lazy { DerivativeStructure(parameters.size, order) }
- public override val one: DerivativeStructure by lazy { DerivativeStructure(parameters.size, order, 1.0) }
-
- private val variables: Map = parameters.mapValues { (key, value) ->
- DerivativeStructure(parameters.size, order, parameters.keys.indexOf(key), value)
- }
-
- public val variable: ReadOnlyProperty = ReadOnlyProperty { _, property ->
- variables[property.name] ?: error("A variable with name ${property.name} does not exist")
- }
-
- public fun variable(name: String, default: DerivativeStructure? = null): DerivativeStructure =
- variables[name] ?: default ?: error("A variable with name $name does not exist")
-
- public fun Number.const(): DerivativeStructure = DerivativeStructure(order, parameters.size, toDouble())
- public fun DerivativeStructure.deriv(parName: String, order: Int = 1): Double = deriv(mapOf(parName to order))
-
- public fun DerivativeStructure.deriv(orders: Map): Double {
- return getPartialDerivative(*parameters.keys.map { orders[it] ?: 0 }.toIntArray())
- }
-
- public fun DerivativeStructure.deriv(vararg orders: Pair): Double = deriv(mapOf(*orders))
- public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b)
-
- public override fun multiply(a: DerivativeStructure, k: Number): DerivativeStructure = when (k) {
- is Double -> a.multiply(k)
- is Int -> a.multiply(k)
- else -> a.multiply(k.toDouble())
- }
-
- public override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b)
- public override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b)
- public override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin()
- public override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos()
- public override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.tan()
- public override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin()
- public override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos()
- public override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan()
- public override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh()
- public override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh()
- public override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh()
- public override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.asinh()
- public override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.acosh()
- public override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.atanh()
-
- public override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) {
- is Double -> arg.pow(pow)
- is Int -> arg.pow(pow)
- else -> arg.pow(pow.toDouble())
- }
-
- public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure = arg.pow(pow)
- public override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp()
- public override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log()
- public override operator fun DerivativeStructure.plus(b: Number): DerivativeStructure = add(b.toDouble())
- public override operator fun DerivativeStructure.minus(b: Number): DerivativeStructure = subtract(b.toDouble())
- public override operator fun Number.plus(b: DerivativeStructure): DerivativeStructure = b + this
- public override operator fun Number.minus(b: DerivativeStructure): DerivativeStructure = b - this
-}
-
-/**
- * A constructs that creates a derivative structure with required order on-demand
- */
-public class DiffExpression(public val function: DerivativeStructureField.() -> DerivativeStructure) :
- Expression {
- public override operator fun invoke(arguments: Map): Double = DerivativeStructureField(
- 0,
- arguments
- ).function().value
-
- /**
- * Get the derivative expression with given orders
- * TODO make result [DiffExpression]
- */
- public fun derivative(orders: Map): Expression = Expression { arguments ->
- (DerivativeStructureField(orders.values.maxOrNull() ?: 0, arguments)) { function().deriv(orders) }
- }
-
- //TODO add gradient and maybe other vector operators
-}
-
-public fun DiffExpression.derivative(vararg orders: Pair): Expression = derivative(mapOf(*orders))
-public fun DiffExpression.derivative(name: String): Expression = derivative(name to 1)
-
-/**
- * A context for [DiffExpression] (not to be confused with [DerivativeStructure])
- */
-public object DiffExpressionAlgebra : ExpressionAlgebra, Field {
- public override val zero: DiffExpression = DiffExpression { 0.0.const() }
- public override val one: DiffExpression = DiffExpression { 1.0.const() }
-
- public override fun variable(name: String, default: Double?): DiffExpression =
- DiffExpression { variable(name, default?.const()) }
-
- public override fun const(value: Double): DiffExpression = DiffExpression { value.const() }
-
- public override fun add(a: DiffExpression, b: DiffExpression): DiffExpression =
- DiffExpression { a.function(this) + b.function(this) }
-
- public override fun multiply(a: DiffExpression, k: Number): DiffExpression = DiffExpression { a.function(this) * k }
-
- public override fun multiply(a: DiffExpression, b: DiffExpression): DiffExpression =
- DiffExpression { a.function(this) * b.function(this) }
-
- public override fun divide(a: DiffExpression, b: DiffExpression): DiffExpression =
- DiffExpression { a.function(this) / b.function(this) }
-}
diff --git a/kmath-commons/src/main/kotlin/kscience/kmath/commons/optimization/CMOptimizationProblem.kt b/kmath-commons/src/main/kotlin/kscience/kmath/commons/optimization/CMOptimizationProblem.kt
new file mode 100644
index 000000000..d6f79529a
--- /dev/null
+++ b/kmath-commons/src/main/kotlin/kscience/kmath/commons/optimization/CMOptimizationProblem.kt
@@ -0,0 +1,110 @@
+package kscience.kmath.commons.optimization
+
+import kscience.kmath.expressions.*
+import kscience.kmath.stat.OptimizationFeature
+import kscience.kmath.stat.OptimizationProblem
+import kscience.kmath.stat.OptimizationProblemFactory
+import kscience.kmath.stat.OptimizationResult
+import org.apache.commons.math3.optim.*
+import org.apache.commons.math3.optim.nonlinear.scalar.GoalType
+import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer
+import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction
+import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient
+import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer
+import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex
+import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex
+import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
+import kotlin.reflect.KClass
+
+public operator fun PointValuePair.component1(): DoubleArray = point
+public operator fun PointValuePair.component2(): Double = value
+
+public class CMOptimizationProblem(override val symbols: List, ) :
+ OptimizationProblem, SymbolIndexer, OptimizationFeature {
+ private val optimizationData: HashMap, OptimizationData> = HashMap()
+ private var optimizatorBuilder: (() -> MultivariateOptimizer)? = null
+ public var convergenceChecker: ConvergenceChecker = SimpleValueChecker(DEFAULT_RELATIVE_TOLERANCE,
+ DEFAULT_ABSOLUTE_TOLERANCE, DEFAULT_MAX_ITER)
+
+ public fun addOptimizationData(data: OptimizationData) {
+ optimizationData[data::class] = data
+ }
+
+ init {
+ addOptimizationData(MaxEval.unlimited())
+ }
+
+ public fun exportOptimizationData(): List = optimizationData.values.toList()
+
+ public override fun initialGuess(map: Map): Unit {
+ addOptimizationData(InitialGuess(map.toDoubleArray()))
+ }
+
+ public override fun expression(expression: Expression): Unit {
+ val objectiveFunction = ObjectiveFunction {
+ val args = it.toMap()
+ expression(args)
+ }
+ addOptimizationData(objectiveFunction)
+ }
+
+ public override fun diffExpression(expression: DifferentiableExpression>) {
+ expression(expression)
+ val gradientFunction = ObjectiveFunctionGradient {
+ val args = it.toMap()
+ DoubleArray(symbols.size) { index ->
+ expression.derivative(symbols[index])(args)
+ }
+ }
+ addOptimizationData(gradientFunction)
+ if (optimizatorBuilder == null) {
+ optimizatorBuilder = {
+ NonLinearConjugateGradientOptimizer(
+ NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES,
+ convergenceChecker
+ )
+ }
+ }
+ }
+
+ public fun simplex(simplex: AbstractSimplex) {
+ addOptimizationData(simplex)
+ //Set optimization builder to simplex if it is not present
+ if (optimizatorBuilder == null) {
+ optimizatorBuilder = { SimplexOptimizer(convergenceChecker) }
+ }
+ }
+
+ public fun simplexSteps(steps: Map) {
+ simplex(NelderMeadSimplex(steps.toDoubleArray()))
+ }
+
+ public fun goal(goalType: GoalType) {
+ addOptimizationData(goalType)
+ }
+
+ public fun optimizer(block: () -> MultivariateOptimizer) {
+ optimizatorBuilder = block
+ }
+
+ override fun update(result: OptimizationResult) {
+ initialGuess(result.point)
+ }
+
+ override fun optimize(): OptimizationResult {
+ val optimizer = optimizatorBuilder?.invoke() ?: error("Optimizer not defined")
+ val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray())
+ return OptimizationResult(point.toMap(), value, setOf(this))
+ }
+
+ public companion object : OptimizationProblemFactory {
+ public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4
+ public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4
+ public const val DEFAULT_MAX_ITER: Int = 1000
+
+ override fun build(symbols: List): CMOptimizationProblem = CMOptimizationProblem(symbols)
+ }
+}
+
+public fun CMOptimizationProblem.initialGuess(vararg pairs: Pair): Unit = initialGuess(pairs.toMap())
+public fun CMOptimizationProblem.simplexSteps(vararg pairs: Pair): Unit = simplexSteps(pairs.toMap())
diff --git a/kmath-commons/src/main/kotlin/kscience/kmath/commons/optimization/cmFit.kt b/kmath-commons/src/main/kotlin/kscience/kmath/commons/optimization/cmFit.kt
new file mode 100644
index 000000000..b8e8bfd4b
--- /dev/null
+++ b/kmath-commons/src/main/kotlin/kscience/kmath/commons/optimization/cmFit.kt
@@ -0,0 +1,67 @@
+package kscience.kmath.commons.optimization
+
+import kscience.kmath.commons.expressions.DerivativeStructureField
+import kscience.kmath.expressions.DifferentiableExpression
+import kscience.kmath.expressions.Expression
+import kscience.kmath.expressions.Symbol
+import kscience.kmath.stat.Fitting
+import kscience.kmath.stat.OptimizationResult
+import kscience.kmath.stat.optimizeWith
+import kscience.kmath.structures.Buffer
+import kscience.kmath.structures.asBuffer
+import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
+import org.apache.commons.math3.optim.nonlinear.scalar.GoalType
+
+/**
+ * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
+ */
+public fun Fitting.chiSquared(
+ x: Buffer,
+ y: Buffer,
+ yErr: Buffer,
+ model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure,
+): DifferentiableExpression> = chiSquared(DerivativeStructureField, x, y, yErr, model)
+
+/**
+ * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
+ */
+public fun Fitting.chiSquared(
+ x: Iterable,
+ y: Iterable,
+ yErr: Iterable,
+ model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure,
+): DifferentiableExpression> = chiSquared(
+ DerivativeStructureField,
+ x.toList().asBuffer(),
+ y.toList().asBuffer(),
+ yErr.toList().asBuffer(),
+ model
+)
+
+/**
+ * Optimize expression without derivatives
+ */
+public fun Expression.optimize(
+ vararg symbols: Symbol,
+ configuration: CMOptimizationProblem.() -> Unit,
+): OptimizationResult = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration)
+
+/**
+ * Optimize differentiable expression
+ */
+public fun DifferentiableExpression>.optimize(
+ vararg symbols: Symbol,
+ configuration: CMOptimizationProblem.() -> Unit,
+): OptimizationResult = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration)
+
+public fun DifferentiableExpression>.minimize(
+ vararg startPoint: Pair,
+ configuration: CMOptimizationProblem.() -> Unit = {},
+): OptimizationResult {
+ require(startPoint.isNotEmpty()) { "Must provide a list of symbols for optimization" }
+ val problem = CMOptimizationProblem(startPoint.map { it.first }).apply(configuration)
+ problem.diffExpression(this)
+ problem.initialGuess(startPoint.toMap())
+ problem.goal(GoalType.MINIMIZE)
+ return problem.optimize()
+}
\ No newline at end of file
diff --git a/kmath-commons/src/main/kotlin/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt
index 58609deae..1eab5f2bd 100644
--- a/kmath-commons/src/main/kotlin/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt
+++ b/kmath-commons/src/main/kotlin/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt
@@ -1,9 +1,10 @@
package kscience.kmath.commons.random
-import kscience.kmath.prob.RandomGenerator
+import kscience.kmath.stat.RandomGenerator
-public class CMRandomGeneratorWrapper(public val factory: (IntArray) -> RandomGenerator) :
- org.apache.commons.math3.random.RandomGenerator {
+public class CMRandomGeneratorWrapper(
+ public val factory: (IntArray) -> RandomGenerator,
+) : org.apache.commons.math3.random.RandomGenerator {
private var generator: RandomGenerator = factory(intArrayOf())
public override fun nextBoolean(): Boolean = generator.nextBoolean()
diff --git a/kmath-commons/src/test/kotlin/kscience/kmath/commons/expressions/AutoDiffTest.kt b/kmath-commons/src/test/kotlin/kscience/kmath/commons/expressions/AutoDiffTest.kt
deleted file mode 100644
index f905e6818..000000000
--- a/kmath-commons/src/test/kotlin/kscience/kmath/commons/expressions/AutoDiffTest.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package kscience.kmath.commons.expressions
-
-import kscience.kmath.expressions.invoke
-import kotlin.contracts.InvocationKind
-import kotlin.contracts.contract
-import kotlin.test.Test
-import kotlin.test.assertEquals
-
-internal inline fun diff(
- order: Int,
- vararg parameters: Pair,
- block: DerivativeStructureField.() -> R
-): R {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return DerivativeStructureField(order, mapOf(*parameters)).run(block)
-}
-
-internal class AutoDiffTest {
- @Test
- fun derivativeStructureFieldTest() {
- val res = diff(3, "x" to 1.0, "y" to 1.0) {
- val x by variable
- val y = variable("y")
- val z = x * (-sin(x * y) + y)
- z.deriv("x")
- }
- }
-
- @Test
- fun autoDifTest() {
- val f = DiffExpression {
- val x by variable
- val y by variable
- x.pow(2) + 2 * x * y + y.pow(2) + 1
- }
-
- assertEquals(10.0, f("x" to 1.0, "y" to 2.0))
- assertEquals(6.0, f.derivative("x")("x" to 1.0, "y" to 2.0))
- }
-}
diff --git a/kmath-commons/src/test/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt b/kmath-commons/src/test/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt
new file mode 100644
index 000000000..7511a38ed
--- /dev/null
+++ b/kmath-commons/src/test/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt
@@ -0,0 +1,50 @@
+package kscience.kmath.commons.expressions
+
+import kscience.kmath.expressions.*
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFails
+
+internal inline fun diff(
+ order: Int,
+ vararg parameters: Pair,
+ block: DerivativeStructureField.() -> Unit,
+): Unit {
+ contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
+ DerivativeStructureField(order, mapOf(*parameters)).run(block)
+}
+
+internal class AutoDiffTest {
+ private val x by symbol
+ private val y by symbol
+
+ @Test
+ fun derivativeStructureFieldTest() {
+ diff(2, x to 1.0, y to 1.0) {
+ val x = bind(x)//by binding()
+ val y = symbol("y")
+ val z = x * (-sin(x * y) + y) + 2.0
+ println(z.derivative(x))
+ println(z.derivative(y,x))
+ assertEquals(z.derivative(x, y), z.derivative(y, x))
+ //check that improper order cause failure
+ assertFails { z.derivative(x,x,y) }
+ }
+ }
+
+ @Test
+ fun autoDifTest() {
+ val f = DerivativeStructureExpression {
+ val x by binding()
+ val y by binding()
+ x.pow(2) + 2 * x * y + y.pow(2) + 1
+ }
+
+ assertEquals(10.0, f(x to 1.0, y to 2.0))
+ assertEquals(6.0, f.derivative(x)(x to 1.0, y to 2.0))
+ assertEquals(2.0, f.derivative(x, x)(x to 1.234, y to -2.0))
+ assertEquals(2.0, f.derivative(x, y)(x to 1.0, y to 2.0))
+ }
+}
diff --git a/kmath-commons/src/test/kotlin/kscience/kmath/commons/optimization/OptimizeTest.kt b/kmath-commons/src/test/kotlin/kscience/kmath/commons/optimization/OptimizeTest.kt
new file mode 100644
index 000000000..3290c8f32
--- /dev/null
+++ b/kmath-commons/src/test/kotlin/kscience/kmath/commons/optimization/OptimizeTest.kt
@@ -0,0 +1,68 @@
+package kscience.kmath.commons.optimization
+
+import kscience.kmath.commons.expressions.DerivativeStructureExpression
+import kscience.kmath.expressions.symbol
+import kscience.kmath.stat.Distribution
+import kscience.kmath.stat.Fitting
+import kscience.kmath.stat.RandomGenerator
+import kscience.kmath.stat.normal
+import org.junit.jupiter.api.Test
+import kotlin.math.pow
+
+internal class OptimizeTest {
+ val x by symbol
+ val y by symbol
+
+ val normal = DerivativeStructureExpression {
+ exp(-bind(x).pow(2) / 2) + exp(-bind(y).pow(2) / 2)
+ }
+
+ @Test
+ fun testGradientOptimization() {
+ val result = normal.optimize(x, y) {
+ initialGuess(x to 1.0, y to 1.0)
+ //no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function
+ }
+ println(result.point)
+ println(result.value)
+ }
+
+ @Test
+ fun testSimplexOptimization() {
+ val result = normal.optimize(x, y) {
+ initialGuess(x to 1.0, y to 1.0)
+ simplexSteps(x to 2.0, y to 0.5)
+ //this sets simplex optimizer
+ }
+ println(result.point)
+ println(result.value)
+ }
+
+ @Test
+ fun testCmFit() {
+ val a by symbol
+ val b by symbol
+ val c by symbol
+
+ val sigma = 1.0
+ val generator = Distribution.normal(0.0, sigma)
+ val chain = generator.sample(RandomGenerator.default(112667))
+ val x = (1..100).map(Int::toDouble)
+
+ val y = x.map {
+ it.pow(2) + it + 1 + chain.nextDouble()
+ }
+
+ val yErr = List(x.size) { sigma }
+
+ val chi2 = Fitting.chiSquared(x, y, yErr) { x1 ->
+ val cWithDefault = bindOrNull(c) ?: one
+ bind(a) * x1.pow(2) + bind(b) * x1 + cWithDefault
+ }
+
+ val result = chi2.minimize(a to 1.5, b to 0.9, c to 1.0)
+ println(result)
+ println("Chi2/dof = ${result.value / (x.size - 3)}")
+ }
+
+}
\ No newline at end of file
diff --git a/kmath-core/README.md b/kmath-core/README.md
index 2cf7ed5dc..42a513a10 100644
--- a/kmath-core/README.md
+++ b/kmath-core/README.md
@@ -7,12 +7,12 @@ The core features of KMath:
- [buffers](src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
- [expressions](src/commonMain/kotlin/kscience/kmath/expressions) : Functional Expressions
- [domains](src/commonMain/kotlin/kscience/kmath/domains) : Domains
- - [autodif](src/commonMain/kotlin/kscience/kmath/misc/AutoDiff.kt) : Automatic differentiation
+ - [autodif](src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
> #### Artifact:
>
-> This module artifact: `kscience.kmath:kmath-core:0.2.0-dev-1`.
+> This module artifact: `kscience.kmath:kmath-core:0.2.0-dev-3`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
>
@@ -22,25 +22,28 @@ The core features of KMath:
>
> ```gradle
> repositories {
+> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
> maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
> maven { url 'https://dl.bintray.com/mipt-npm/dev' }
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
+
> }
>
> dependencies {
-> implementation 'kscience.kmath:kmath-core:0.2.0-dev-1'
+> implementation 'kscience.kmath:kmath-core:0.2.0-dev-3'
> }
> ```
> **Gradle Kotlin DSL:**
>
> ```kotlin
> repositories {
+> maven("https://dl.bintray.com/kotlin/kotlin-eap")
> maven("https://dl.bintray.com/mipt-npm/kscience")
> maven("https://dl.bintray.com/mipt-npm/dev")
> maven("https://dl.bintray.com/hotkeytlt/maven")
> }
>
> dependencies {
-> implementation("kscience.kmath:kmath-core:0.2.0-dev-1")
+> implementation("kscience.kmath:kmath-core:0.2.0-dev-3")
> }
> ```
diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts
index 79cfce1f7..7f889d9b4 100644
--- a/kmath-core/build.gradle.kts
+++ b/kmath-core/build.gradle.kts
@@ -49,6 +49,6 @@ readme {
feature(
id = "autodif",
description = "Automatic differentiation",
- ref = "src/commonMain/kotlin/kscience/kmath/misc/AutoDiff.kt"
+ ref = "src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt"
)
}
diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/DifferentiableExpression.kt
new file mode 100644
index 000000000..abce9c4ec
--- /dev/null
+++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/DifferentiableExpression.kt
@@ -0,0 +1,48 @@
+package kscience.kmath.expressions
+
+/**
+ * Represents expression which structure can be differentiated.
+ *
+ * @param T the type this expression takes as argument and returns.
+ * @param R the type of expression this expression can be differentiated to.
+ */
+public interface DifferentiableExpression> : Expression {
+ /**
+ * Differentiates this expression by ordered collection of [symbols].
+ *
+ * @param symbols the symbols.
+ * @return the derivative or `null`.
+ */
+ public fun derivativeOrNull(symbols: List): R?
+}
+
+public fun > DifferentiableExpression.derivative(symbols: List): R =
+ derivativeOrNull(symbols) ?: error("Derivative by symbols $symbols not provided")
+
+public fun > DifferentiableExpression.derivative(vararg symbols: Symbol): R =
+ derivative(symbols.toList())
+
+public fun > DifferentiableExpression.derivative(name: String): R =
+ derivative(StringSymbol(name))
+
+/**
+ * A [DifferentiableExpression] that defines only first derivatives
+ */
+public abstract class FirstDerivativeExpression> : DifferentiableExpression {
+ /**
+ * Returns first derivative of this expression by given [symbol].
+ */
+ public abstract fun derivativeOrNull(symbol: Symbol): R?
+
+ public final override fun derivativeOrNull(symbols: List): R? {
+ val dSymbol = symbols.firstOrNull() ?: return null
+ return derivativeOrNull(dSymbol)
+ }
+}
+
+/**
+ * A factory that converts an expression in autodiff variables to a [DifferentiableExpression]
+ */
+public fun interface AutoDiffProcessor, out R : Expression> {
+ public fun process(function: A.() -> I): DifferentiableExpression
+}
diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/Expression.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/Expression.kt
index 5ade9e3ca..98940e767 100644
--- a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/Expression.kt
+++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/Expression.kt
@@ -1,9 +1,30 @@
package kscience.kmath.expressions
import kscience.kmath.operations.Algebra
+import kotlin.jvm.JvmName
+import kotlin.properties.ReadOnlyProperty
/**
- * An elementary function that could be invoked on a map of arguments
+ * A marker interface for a symbol. A symbol mus have an identity
+ */
+public interface Symbol {
+ /**
+ * Identity object for the symbol. Two symbols with the same identity are considered to be the same symbol.
+ */
+ public val identity: String
+}
+
+/**
+ * A [Symbol] with a [String] identity
+ */
+public inline class StringSymbol(override val identity: String) : Symbol {
+ override fun toString(): String = identity
+}
+
+/**
+ * An elementary function that could be invoked on a map of arguments.
+ *
+ * @param T the type this expression takes as argument and returns.
*/
public fun interface Expression {
/**
@@ -12,30 +33,75 @@ public fun interface Expression {
* @param arguments the map of arguments.
* @return the value.
*/
- public operator fun invoke(arguments: Map): T
-
- public companion object
+ public operator fun invoke(arguments: Map): T
}
+/**
+ * Calls this expression without providing any arguments.
+ *
+ * @return a value.
+ */
+public operator fun Expression.invoke(): T = invoke(emptyMap())
+
/**
* Calls this expression from arguments.
*
- * @param pairs the pair of arguments' names to values.
- * @return the value.
+ * @param pairs the pairs of arguments to values.
+ * @return a value.
*/
-public operator fun Expression.invoke(vararg pairs: Pair): T = invoke(mapOf(*pairs))
+@JvmName("callBySymbol")
+public operator fun Expression.invoke(vararg pairs: Pair): T = invoke(mapOf(*pairs))
+
+/**
+ * Calls this expression from arguments.
+ *
+ * @param pairs the pairs of arguments' names to values.
+ * @return a value.
+ */
+@JvmName("callByString")
+public operator fun Expression.invoke(vararg pairs: Pair): T =
+ invoke(mapOf(*pairs).mapKeys { StringSymbol(it.key) })
+
/**
* A context for expression construction
+ *
+ * @param T type of the constants for the expression
+ * @param E type of the actual expression state
*/
-public interface ExpressionAlgebra : Algebra {
+public interface ExpressionAlgebra : Algebra {
/**
- * Introduce a variable into expression context
+ * Bind a given [Symbol] to this context variable and produce context-specific object. Return null if symbol could not be bound in current context.
*/
- public fun variable(name: String, default: T? = null): E
+ public fun bindOrNull(symbol: Symbol): E?
+
+ /**
+ * Bind a string to a context using [StringSymbol]
+ */
+ override fun symbol(value: String): E = bind(StringSymbol(value))
/**
* A constant expression which does not depend on arguments
*/
public fun const(value: T): E
}
+
+/**
+ * Bind a given [Symbol] to this context variable and produce context-specific object.
+ */
+public fun ExpressionAlgebra.bind(symbol: Symbol): E =
+ bindOrNull(symbol) ?: error("Symbol $symbol could not be bound to $this")
+
+/**
+ * A delegate to create a symbol with a string identity in this scope
+ */
+public val symbol: ReadOnlyProperty = ReadOnlyProperty { _, property ->
+ StringSymbol(property.name)
+}
+
+/**
+ * Bind a symbol by name inside the [ExpressionAlgebra]
+ */
+public fun ExpressionAlgebra.binding(): ReadOnlyProperty = ReadOnlyProperty { _, property ->
+ bind(StringSymbol(property.name)) ?: error("A variable with name ${property.name} does not exist")
+}
diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt
index 5b050dd36..0630e8e4b 100644
--- a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt
+++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt
@@ -2,67 +2,43 @@ package kscience.kmath.expressions
import kscience.kmath.operations.*
-internal class FunctionalUnaryOperation(val context: Algebra, val name: String, private val expr: Expression) :
- Expression {
- override operator fun invoke(arguments: Map): T =
- context.unaryOperation(name, expr.invoke(arguments))
-}
-
-internal class FunctionalBinaryOperation(
- val context: Algebra,
- val name: String,
- val first: Expression,
- val second: Expression
-) : Expression {
- override operator fun invoke(arguments: Map): T =
- context.binaryOperation(name, first.invoke(arguments), second.invoke(arguments))
-}
-
-internal class FunctionalVariableExpression(val name: String, val default: T? = null) : Expression {
- override operator fun invoke(arguments: Map): T =
- arguments[name] ?: default ?: error("Parameter not found: $name")
-}
-
-internal class FunctionalConstantExpression(val value: T) : Expression {
- override operator fun invoke(arguments: Map): T = value
-}
-
-internal class FunctionalConstProductExpression(
- val context: Space,
- private val expr: Expression,
- val const: Number
-) : Expression {
- override operator fun invoke(arguments: Map): T = context.multiply(expr.invoke(arguments), const)
-}
-
/**
* A context class for [Expression] construction.
*
* @param algebra The algebra to provide for Expressions built.
*/
-public abstract class FunctionalExpressionAlgebra>(public val algebra: A) :
- ExpressionAlgebra> {
+public abstract class FunctionalExpressionAlgebra>(
+ public val algebra: A,
+) : ExpressionAlgebra> {
/**
* Builds an Expression of constant expression which does not depend on arguments.
*/
- public override fun const(value: T): Expression = FunctionalConstantExpression(value)
+ public override fun const(value: T): Expression = Expression { value }
/**
* Builds an Expression to access a variable.
*/
- public override fun variable(name: String, default: T?): Expression = FunctionalVariableExpression(name, default)
+ public override fun bindOrNull(symbol: Symbol): Expression? = Expression { arguments ->
+ arguments[symbol] ?: error("Argument not found: $symbol")
+ }
/**
* Builds an Expression of dynamic call of binary operation [operation] on [left] and [right].
*/
- public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression =
- FunctionalBinaryOperation(algebra, operation, left, right)
+ public override fun binaryOperation(
+ operation: String,
+ left: Expression,
+ right: Expression,
+ ): Expression = Expression { arguments ->
+ algebra.binaryOperation(operation, left.invoke(arguments), right.invoke(arguments))
+ }
/**
* Builds an Expression of dynamic call of unary operation with name [operation] on [arg].
*/
- public override fun unaryOperation(operation: String, arg: Expression): Expression =
- FunctionalUnaryOperation(algebra, operation, arg)
+ public override fun unaryOperation(operation: String, arg: Expression): Expression = Expression { arguments ->
+ algebra.unaryOperation(operation, arg.invoke(arguments))
+ }
}
/**
@@ -81,8 +57,9 @@ public open class FunctionalExpressionSpace>(algebra: A) :
/**
* Builds an Expression of multiplication of expression by number.
*/
- public override fun multiply(a: Expression, k: Number): Expression =
- FunctionalConstProductExpression(algebra, a, k)
+ public override fun multiply(a: Expression, k: Number): Expression = Expression { arguments ->
+ algebra.multiply(a.invoke(arguments), k)
+ }
public operator fun Expression.plus(arg: T): Expression = this + const(arg)
public operator fun Expression