diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f39e12a12..9a9f04621 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,9 +13,11 @@ jobs:
- name: Checkout the repo
uses: actions/checkout@v2
- name: Set up JDK 11
- uses: actions/setup-java@v1
+ uses: DeLaGuardo/setup-graalvm@4.0
with:
- java-version: 11
+ graalvm: 21.1.0
+ java: java11
+ arch: amd64
- name: Add msys to path
if: matrix.os == 'windows-latest'
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 110537a10..86fdac6a6 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -16,9 +16,7 @@ jobs:
with:
java-version: 11
- name: Build
- run: |
- ./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace
- mv build/dokka/htmlMultiModule/-modules.html build/dokka/htmlMultiModule/index.html
+ run: ./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace
- name: Deploy to GitHub Pages
uses: JamesIves/github-pages-deploy-action@4.1.0
with:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index ca374574e..c5c110e89 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -18,9 +18,11 @@ jobs:
- name: Checkout the repo
uses: actions/checkout@v2
- name: Set up JDK 11
- uses: actions/setup-java@v1
+ uses: DeLaGuardo/setup-graalvm@4.0
with:
- java-version: 11
+ graalvm: 21.1.0
+ java: java11
+ arch: amd64
- name: Add msys to path
if: matrix.os == 'windows-latest'
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
diff --git a/.gitignore b/.gitignore
index 2a13b9e3c..d6c4af4e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ out/
.idea/
!.idea/copyright/
+!.idea/scopes/
.vscode/
diff --git a/.idea/copyright/kmath.xml b/.idea/copyright/kmath.xml
index 6fe438777..17e44e4d0 100644
--- a/.idea/copyright/kmath.xml
+++ b/.idea/copyright/kmath.xml
@@ -1,6 +1,6 @@
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
index 6cc25cb4a..b538bdf41 100644
--- a/.idea/copyright/profiles_settings.xml
+++ b/.idea/copyright/profiles_settings.xml
@@ -1,7 +1,21 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/scopes/Apply_copyright.xml b/.idea/scopes/Apply_copyright.xml
new file mode 100644
index 000000000..0eb589133
--- /dev/null
+++ b/.idea/scopes/Apply_copyright.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c3bd2641a..286511327 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,8 @@
- Blocking chains and Statistics
- Multiplatform integration
- Integration for any Field element
+- Extended operations for ND4J fields
+- Jupyter Notebook integration module (kmath-jupyter)
### Changed
- Exponential operations merged with hyperbolic functions
@@ -22,6 +24,8 @@
- Redesign advanced Chain API
- Redesign MST. Remove MSTExpression.
- Move MST to core
+- Separated benchmarks and examples
+- Rewritten EJML module without ejml-simple
### Deprecated
@@ -30,6 +34,8 @@
- Number multiplication and division in main Algebra chain
- `contentEquals` from Buffer. It moved to the companion.
- MSTExpression
+- Expression algebra builders
+- Comples and Quaternion no longer are elements.
### Fixed
- Ring inherits RingOperations, not GroupOperations
diff --git a/README.md b/README.md
index 0210b4caf..c8da21b64 100644
--- a/README.md
+++ b/README.md
@@ -76,6 +76,12 @@ KMath is a modular library. Different modules provide different features with di
+* ### [benchmarks](benchmarks)
+>
+>
+> **Maturity**: EXPERIMENTAL
+
+
* ### [examples](examples)
>
>
@@ -85,15 +91,13 @@ KMath is a modular library. Different modules provide different features with di
* ### [kmath-ast](kmath-ast)
>
>
-> **Maturity**: PROTOTYPE
+> **Maturity**: EXPERIMENTAL
>
> **Features:**
-> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
-> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
-> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
-> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
+> - [expression-language](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
+> - [rendering](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering
@@ -150,9 +154,9 @@ performance calculations to code generation.
> **Maturity**: PROTOTYPE
>
> **Features:**
-> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : The Point implementation using SimpleMatrix.
-> - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : The Matrix implementation using SimpleMatrix.
-> - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : The LinearSpace implementation using SimpleMatrix.
+> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : Point implementations.
+> - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : Matrix implementation.
+> - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : LinearSpace implementations.
@@ -196,6 +200,12 @@ One can still use generic algebras though.
> **Maturity**: PROTOTYPE
+* ### [kmath-jupyter](kmath-jupyter)
+>
+>
+> **Maturity**: PROTOTYPE
+
+
* ### [kmath-kotlingrad](kmath-kotlingrad)
>
>
@@ -226,6 +236,18 @@ One can still use generic algebras though.
> **Maturity**: EXPERIMENTAL
+* ### [kmath-tensors](kmath-tensors)
+>
+>
+> **Maturity**: PROTOTYPE
+>
+> **Features:**
+> - [tensor algebra](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.)
+> - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting.
+> - [linear algebra operations](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc.
+
+
+
* ### [kmath-viktor](kmath-viktor)
>
>
@@ -266,8 +288,8 @@ repositories {
}
dependencies {
- api("space.kscience:kmath-core:0.3.0-dev-6")
- // api("space.kscience:kmath-core-jvm:0.3.0-dev-6") for jvm-specific version
+ api("space.kscience:kmath-core:0.3.0-dev-8")
+ // api("space.kscience:kmath-core-jvm:0.3.0-dev-8") for jvm-specific version
}
```
diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts
new file mode 100644
index 000000000..98ffc5a96
--- /dev/null
+++ b/benchmarks/build.gradle.kts
@@ -0,0 +1,126 @@
+plugins {
+ kotlin("multiplatform")
+ kotlin("plugin.allopen")
+ id("org.jetbrains.kotlinx.benchmark")
+}
+
+allOpen.annotation("org.openjdk.jmh.annotations.State")
+sourceSets.register("benchmarks")
+
+repositories {
+ mavenCentral()
+ maven("https://repo.kotlin.link")
+ maven("https://clojars.org/repo")
+ maven("https://jitpack.io")
+ maven("http://logicrunch.research.it.uu.se/maven") {
+ isAllowInsecureProtocol = true
+ }
+}
+
+kotlin {
+ jvm()
+
+ sourceSets {
+ val commonMain by getting {
+ dependencies {
+ implementation(project(":kmath-ast"))
+ implementation(project(":kmath-core"))
+ implementation(project(":kmath-coroutines"))
+ implementation(project(":kmath-complex"))
+ implementation(project(":kmath-stat"))
+ implementation(project(":kmath-dimensions"))
+ implementation(project(":kmath-for-real"))
+ implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.0")
+ }
+ }
+
+ val jvmMain by getting {
+ dependencies {
+ implementation(project(":kmath-commons"))
+ implementation(project(":kmath-ejml"))
+ implementation(project(":kmath-nd4j"))
+ implementation(project(":kmath-kotlingrad"))
+ implementation(project(":kmath-viktor"))
+ implementation("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")
+ }
+ }
+ }
+}
+
+// Configure benchmark
+benchmark {
+ // Setup configurations
+ targets {
+ register("jvm")
+ }
+
+ fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() {
+ warmups = 1
+ iterations = 5
+ iterationTime = 1000
+ iterationTimeUnit = "ms"
+ }
+
+ configurations.register("buffer") {
+ commonConfiguration()
+ include("BufferBenchmark")
+ }
+
+ configurations.register("dot") {
+ commonConfiguration()
+ include("DotBenchmark")
+ }
+
+ configurations.register("expressions") {
+ commonConfiguration()
+ include("ExpressionsInterpretersBenchmark")
+ }
+
+ configurations.register("matrixInverse") {
+ commonConfiguration()
+ include("MatrixInverseBenchmark")
+ }
+
+ configurations.register("bigInt") {
+ commonConfiguration()
+ include("BigIntBenchmark")
+ }
+}
+
+// Fix kotlinx-benchmarks bug
+afterEvaluate {
+ val jvmBenchmarkJar by tasks.getting(org.gradle.jvm.tasks.Jar::class) {
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ }
+}
+
+
+kotlin.sourceSets.all {
+ with(languageSettings) {
+ useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
+ useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
+ useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
+ }
+}
+
+tasks.withType {
+ kotlinOptions {
+ jvmTarget = "11"
+ freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
+ }
+}
+
+
+readme {
+ maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
+}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt
similarity index 100%
rename from examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt
rename to benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
similarity index 58%
rename from examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
rename to benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
index 672efd5c2..2076aedc7 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
@@ -5,19 +5,26 @@
package space.kscience.kmath.benchmarks
+
import kotlinx.benchmark.Blackhole
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
+import space.kscience.kmath.operations.BigInt
import space.kscience.kmath.operations.BigIntField
import space.kscience.kmath.operations.JBigIntegerField
import space.kscience.kmath.operations.invoke
+private fun BigInt.pow(power: Int): BigInt = modPow(BigIntField.number(power), BigInt.ZERO)
+
@State(Scope.Benchmark)
internal class BigIntBenchmark {
val kmNumber = BigIntField.number(Int.MAX_VALUE)
val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE)
+ val largeKmNumber = BigIntField { number(11).pow(100_000) }
+ val largeJvmNumber = JBigIntegerField { number(11).pow(100_000) }
+ val bigExponent = 50_000
@Benchmark
fun kmAdd(blackhole: Blackhole) = BigIntField {
@@ -34,8 +41,28 @@ internal class BigIntBenchmark {
blackhole.consume(kmNumber * kmNumber * kmNumber)
}
+ @Benchmark
+ fun kmMultiplyLarge(blackhole: Blackhole) = BigIntField {
+ blackhole.consume(largeKmNumber*largeKmNumber)
+ }
+
@Benchmark
fun jvmMultiply(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume(jvmNumber * jvmNumber * jvmNumber)
}
-}
\ No newline at end of file
+
+ @Benchmark
+ fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerField {
+ blackhole.consume(largeJvmNumber*largeJvmNumber)
+ }
+
+// @Benchmark
+// fun kmPower(blackhole: Blackhole) = BigIntField {
+// blackhole.consume(kmNumber.pow(bigExponent))
+// }
+//
+// @Benchmark
+// fun jvmPower(blackhole: Blackhole) = JBigIntegerField {
+// blackhole.consume(jvmNumber.pow(bigExponent))
+// }
+}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
similarity index 100%
rename from examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
rename to benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
similarity index 88%
rename from examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
rename to benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
index 23e73cb5f..2c5a03a97 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
@@ -10,7 +10,7 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.commons.linear.CMLinearSpace
-import space.kscience.kmath.ejml.EjmlLinearSpace
+import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
import space.kscience.kmath.linear.LinearSpace
import space.kscience.kmath.linear.invoke
import space.kscience.kmath.operations.DoubleField
@@ -29,8 +29,8 @@ internal class DotBenchmark {
val cmMatrix1 = CMLinearSpace { matrix1.toCM() }
val cmMatrix2 = CMLinearSpace { matrix2.toCM() }
- val ejmlMatrix1 = EjmlLinearSpace { matrix1.toEjml() }
- val ejmlMatrix2 = EjmlLinearSpace { matrix2.toEjml() }
+ val ejmlMatrix1 = EjmlLinearSpaceDDRM { matrix1.toEjml() }
+ val ejmlMatrix2 = EjmlLinearSpaceDDRM { matrix2.toEjml() }
}
@Benchmark
@@ -42,14 +42,14 @@ internal class DotBenchmark {
@Benchmark
fun ejmlDot(blackhole: Blackhole) {
- EjmlLinearSpace {
+ EjmlLinearSpaceDDRM {
blackhole.consume(ejmlMatrix1 dot ejmlMatrix2)
}
}
@Benchmark
fun ejmlDotWithConversion(blackhole: Blackhole) {
- EjmlLinearSpace {
+ EjmlLinearSpaceDDRM {
blackhole.consume(matrix1 dot matrix2)
}
}
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
new file mode 100644
index 000000000..942fba308
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+import kotlinx.benchmark.Benchmark
+import kotlinx.benchmark.Blackhole
+import kotlinx.benchmark.Scope
+import kotlinx.benchmark.State
+import space.kscience.kmath.asm.compileToExpression
+import space.kscience.kmath.expressions.*
+import space.kscience.kmath.misc.Symbol
+import space.kscience.kmath.misc.symbol
+import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.bindSymbol
+import space.kscience.kmath.operations.invoke
+import kotlin.random.Random
+
+@State(Scope.Benchmark)
+internal class ExpressionsInterpretersBenchmark {
+ @Benchmark
+ fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, blackhole)
+
+ @Benchmark
+ fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, blackhole)
+
+ @Benchmark
+ fun asmExpression(blackhole: Blackhole) = invokeAndSum(asm, blackhole)
+
+ @Benchmark
+ fun rawExpression(blackhole: Blackhole) = invokeAndSum(raw, blackhole)
+
+ private fun invokeAndSum(expr: Expression, blackhole: Blackhole) {
+ val random = Random(0)
+ var sum = 0.0
+
+ repeat(times) {
+ sum += expr(x to random.nextDouble())
+ }
+
+ blackhole.consume(sum)
+ }
+
+ private companion object {
+ private val x: Symbol by symbol
+ private val algebra: DoubleField = DoubleField
+ private const val times = 1_000_000
+
+ private val functional: Expression = DoubleField.expressionInExtendedField {
+ bindSymbol(x) * number(2.0) + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x))
+ }
+
+ private val node = MstExtendedField {
+ bindSymbol(x) * 2.0 + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x))
+ }
+
+ private val mst: Expression = node.toExpression(DoubleField)
+ private val asm: Expression = node.compileToExpression(DoubleField)
+
+ private val raw: Expression = Expression { args ->
+ args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 / kotlin.math.sin(args.getValue(x))
+ }
+ }
+}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt
similarity index 63%
rename from examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt
rename to benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt
index d1803e389..7bb32af28 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt
@@ -11,25 +11,26 @@ import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.commons.linear.CMLinearSpace
import space.kscience.kmath.commons.linear.inverse
-import space.kscience.kmath.ejml.EjmlLinearSpace
-import space.kscience.kmath.ejml.inverse
+import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
+import space.kscience.kmath.linear.InverseMatrixFeature
import space.kscience.kmath.linear.LinearSpace
import space.kscience.kmath.linear.inverseWithLup
import space.kscience.kmath.linear.invoke
+import space.kscience.kmath.nd.getFeature
import kotlin.random.Random
@State(Scope.Benchmark)
internal class MatrixInverseBenchmark {
- companion object {
- val random = Random(1224)
- const val dim = 100
+ private companion object {
+ private val random = Random(1224)
+ private const val dim = 100
private val space = LinearSpace.real
//creating invertible matrix
- val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
- val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
- val matrix = space { l dot u }
+ private val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
+ private val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
+ private val matrix = space { l dot u }
}
@Benchmark
@@ -46,8 +47,8 @@ internal class MatrixInverseBenchmark {
@Benchmark
fun ejmlInverse(blackhole: Blackhole) {
- with(EjmlLinearSpace) {
- blackhole.consume(inverse(matrix))
+ with(EjmlLinearSpaceDDRM) {
+ blackhole.consume(matrix.getFeature>()?.inverse)
}
}
}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
similarity index 100%
rename from examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
rename to benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
similarity index 100%
rename from examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
rename to benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
similarity index 100%
rename from examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
rename to benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
diff --git a/build.gradle.kts b/build.gradle.kts
index 9b2200cb4..406a46810 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,53 +1,37 @@
-/*
- * Copyright 2018-2021 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-import org.jetbrains.dokka.gradle.DokkaTask
-import java.net.URL
-
plugins {
id("ru.mipt.npm.gradle.project")
+ kotlin("jupyter.api") apply false
}
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://jitpack.io")
- maven{
- setUrl("http://logicrunch.research.it.uu.se/maven/")
+ maven("http://logicrunch.research.it.uu.se/maven") {
isAllowInsecureProtocol = true
}
+ maven("https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven")
mavenCentral()
}
group = "space.kscience"
- version = "0.3.0-dev-6"
+ version = "0.3.0-dev-8"
}
subprojects {
if (name.startsWith("kmath")) apply()
afterEvaluate {
- tasks.withType {
- dokkaSourceSets.all {
- val readmeFile = File(this@subprojects.projectDir, "./README.md")
- if (readmeFile.exists())
- includes.setFrom(includes + readmeFile.absolutePath)
+ tasks.withType {
+ dependsOn(tasks.getByName("assemble"))
- arrayOf(
- "http://ejml.org/javadoc/",
- "https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/",
- "https://deeplearning4j.org/api/latest/"
- ).map { URL("${it}package-list") to URL(it) }.forEach { (a, b) ->
- externalDocumentationLink {
- packageListUrl.set(a)
- url.set(b)
- }
- }
+ dokkaSourceSets.all {
+ val readmeFile = File(this@subprojects.projectDir, "README.md")
+ if (readmeFile.exists()) includes.setFrom(includes + readmeFile.absolutePath)
+ externalDocumentationLink("http://ejml.org/javadoc/")
+ externalDocumentationLink("https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/")
+ externalDocumentationLink("https://deeplearning4j.org/api/latest/")
+ externalDocumentationLink("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/")
}
}
}
diff --git a/docs/templates/ARTIFACT-TEMPLATE.md b/docs/templates/ARTIFACT-TEMPLATE.md
index 01d9c51da..1bac2a8ff 100644
--- a/docs/templates/ARTIFACT-TEMPLATE.md
+++ b/docs/templates/ARTIFACT-TEMPLATE.md
@@ -6,8 +6,7 @@ The Maven coordinates of this project are `${group}:${name}:${version}`.
```gradle
repositories {
maven { url 'https://repo.kotlin.link' }
- maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
- maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
+ mavenCentral()
}
dependencies {
@@ -18,8 +17,7 @@ dependencies {
```kotlin
repositories {
maven("https://repo.kotlin.link")
- maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
- maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
+ mavenCentral()
}
dependencies {
diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts
index 98d7b7073..1c7caf1b9 100644
--- a/examples/build.gradle.kts
+++ b/examples/build.gradle.kts
@@ -1,36 +1,16 @@
-/*
- * Copyright 2018-2021 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-import ru.mipt.npm.gradle.Maturity
-
plugins {
kotlin("jvm")
- kotlin("plugin.allopen")
- id("org.jetbrains.kotlinx.benchmark")
}
-allOpen.annotation("org.openjdk.jmh.annotations.State")
-sourceSets.register("benchmarks")
-
repositories {
- jcenter()
+ mavenCentral()
maven("https://repo.kotlin.link")
maven("https://clojars.org/repo")
- maven("https://dl.bintray.com/egor-bogomolov/astminer/")
- maven("https://dl.bintray.com/hotkeytlt/maven")
- maven("https://dl.bintray.com/kotlin/kotlin-eap")
- maven("https://dl.bintray.com/kotlin/kotlinx")
- maven("https://dl.bintray.com/mipt-npm/dev")
- maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://jitpack.io")
- maven{
- setUrl("http://logicrunch.research.it.uu.se/maven/")
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers")
+ maven("http://logicrunch.research.it.uu.se/maven") {
isAllowInsecureProtocol = true
}
- mavenCentral()
}
dependencies {
@@ -45,10 +25,10 @@ dependencies {
implementation(project(":kmath-dimensions"))
implementation(project(":kmath-ejml"))
implementation(project(":kmath-nd4j"))
+ implementation(project(":kmath-tensors"))
implementation(project(":kmath-for-real"))
- implementation("org.deeplearning4j:deeplearning4j-core:1.0.0-beta7")
implementation("org.nd4j:nd4j-native:1.0.0-beta7")
// uncomment if your system supports AVX2
@@ -61,62 +41,9 @@ dependencies {
// } 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.3.0")
implementation("org.slf4j:slf4j-simple:1.7.30")
-
// plotting
- implementation("kscience.plotlykt:plotlykt-server:0.3.1-dev")
-
- "benchmarksImplementation"("org.jetbrains.kotlinx:kotlinx.benchmark.runtime-jvm:0.2.0-dev-20")
- "benchmarksImplementation"(sourceSets.main.get().output + sourceSets.main.get().runtimeClasspath)
-}
-
-// Configure benchmark
-benchmark {
- // Setup configurations
- targets.register("benchmarks")
- // This one matches sourceSet name above
-
- configurations.register("buffer") {
- warmups = 1 // number of warmup iterations
- iterations = 3 // number of iterations
- iterationTime = 500 // time in seconds per iteration
- iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
- include("BufferBenchmark")
- }
-
- configurations.register("dot") {
- warmups = 1 // number of warmup iterations
- iterations = 3 // number of iterations
- iterationTime = 500 // time in seconds per iteration
- iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
- include("DotBenchmark")
- }
-
- configurations.register("expressions") {
- warmups = 1 // number of warmup iterations
- iterations = 3 // number of iterations
- iterationTime = 500 // time in seconds per iteration
- iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
- include("ExpressionsInterpretersBenchmark")
- }
-
- configurations.register("matrixInverse") {
- warmups = 1 // number of warmup iterations
- iterations = 3 // number of iterations
- iterationTime = 500 // time in seconds per iteration
- iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
- include("MatrixInverseBenchmark")
- }
-
- configurations.register("bigInt") {
- warmups = 1 // number of warmup iterations
- iterations = 3 // number of iterations
- iterationTime = 500 // time in seconds per iteration
- iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
- include("BigIntBenchmark")
- }
+ implementation("space.kscience:plotlykt-server:0.4.0-dev-2")
}
kotlin.sourceSets.all {
@@ -127,7 +54,7 @@ kotlin.sourceSets.all {
}
}
-tasks.withType {
+tasks.withType {
kotlinOptions{
jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
@@ -135,5 +62,5 @@ tasks.withType {
}
readme {
- maturity = Maturity.EXPERIMENTAL
+ maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
deleted file mode 100644
index d6fde8398..000000000
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
+++ /dev/null
@@ -1,77 +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.benchmarks
-
-import kotlinx.benchmark.Benchmark
-import kotlinx.benchmark.Blackhole
-import kotlinx.benchmark.Scope
-import kotlinx.benchmark.State
-import space.kscience.kmath.asm.compileToExpression
-import space.kscience.kmath.expressions.*
-import space.kscience.kmath.misc.symbol
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.bindSymbol
-import space.kscience.kmath.operations.invoke
-import kotlin.random.Random
-
-@State(Scope.Benchmark)
-internal class ExpressionsInterpretersBenchmark {
- @Benchmark
- fun functionalExpression(blackhole: Blackhole) {
- val expr = algebra.expressionInField {
- val x = bindSymbol(x)
- x * const(2.0) + const(2.0) / x - const(16.0)
- }
-
- invokeAndSum(expr, blackhole)
- }
-
- @Benchmark
- fun mstExpression(blackhole: Blackhole) {
- val expr = MstField {
- val x = bindSymbol(x)
- x * 2.0 + number(2.0) / x - 16.0
- }.toExpression(algebra)
-
- invokeAndSum(expr, blackhole)
- }
-
- @Benchmark
- fun asmExpression(blackhole: Blackhole) {
- val expr = MstField {
- val x = bindSymbol(x)
- x * 2.0 + number(2.0) / x - 16.0
- }.compileToExpression(algebra)
-
- invokeAndSum(expr, blackhole)
- }
-
- @Benchmark
- fun rawExpression(blackhole: Blackhole) {
- val expr = Expression { args ->
- val x = args.getValue(x)
- x * 2.0 + 2.0 / x - 16.0
- }
-
- invokeAndSum(expr, blackhole)
- }
-
- private fun invokeAndSum(expr: Expression, blackhole: Blackhole) {
- val random = Random(0)
- var sum = 0.0
-
- repeat(1000000) {
- sum += expr(x to random.nextDouble())
- }
-
- blackhole.consume(sum)
- }
-
- private companion object {
- private val algebra = DoubleField
- private val x by symbol
- }
-}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
index 4a31f33a3..25f42f5a9 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
@@ -25,5 +25,5 @@ fun main() {
val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField)
- assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
+ assert(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0))
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt
index be4dc461b..028985260 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt
@@ -7,9 +7,6 @@ package space.kscience.kmath.commons.fit
import kotlinx.html.br
import kotlinx.html.h3
-import kscience.plotly.*
-import kscience.plotly.models.ScatterMode
-import kscience.plotly.models.TraceValues
import space.kscience.kmath.commons.optimization.chiSquared
import space.kscience.kmath.commons.optimization.minimize
import space.kscience.kmath.distributions.NormalDistribution
@@ -22,6 +19,9 @@ import space.kscience.kmath.real.step
import space.kscience.kmath.stat.RandomGenerator
import space.kscience.kmath.structures.asIterable
import space.kscience.kmath.structures.toList
+import space.kscience.plotly.*
+import space.kscience.plotly.models.ScatterMode
+import space.kscience.plotly.models.TraceValues
import kotlin.math.pow
import kotlin.math.sqrt
diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
index 90542adf4..6990e8c8f 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.functions
import space.kscience.kmath.integration.integrate
diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt
index bd431c22c..8020df8f6 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.functions
import space.kscience.kmath.integration.integrate
diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
index f7b284e89..a01ea7fe2 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
@@ -22,8 +22,8 @@ fun main() {
return DoubleBuffer(x.size) { i ->
val h = sigma[i] / 5
val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
- val f1 = invoke(x + dVector / 2)
- val f0 = invoke(x - dVector / 2)
+ val f1 = this(x + dVector / 2)
+ val f0 = this(x - dVector / 2)
(f1 - f0) / h
}
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
index cc1f5f680..501bf98db 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
@@ -5,6 +5,7 @@
package space.kscience.kmath.structures
+import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import org.nd4j.linalg.factory.Nd4j
import space.kscience.kmath.nd.*
@@ -22,6 +23,7 @@ internal inline fun measureAndPrint(title: String, block: () -> Unit) {
println("$title completed in $time millis")
}
+@OptIn(DelicateCoroutinesApi::class)
fun main() {
// initializing Nd4j
Nd4j.zeros(0)
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt
new file mode 100644
index 000000000..6fbf16a91
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this 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.operations.invoke
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
+
+
+// Dataset normalization
+
+fun main() {
+
+ // work in context with broadcast methods
+ BroadcastDoubleTensorAlgebra {
+ // take dataset of 5-element vectors from normal distribution
+ val dataset = randomNormal(intArrayOf(100, 5)) * 1.5 // all elements from N(0, 1.5)
+
+ dataset += fromArray(
+ intArrayOf(5),
+ doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // rows means
+ )
+
+
+ // find out mean and standard deviation of each column
+ val mean = dataset.mean(0, false)
+ val std = dataset.std(0, false)
+
+ println("Mean:\n$mean")
+ println("Standard deviation:\n$std")
+
+ // also we can calculate other statistic as minimum and maximum of rows
+ println("Minimum:\n${dataset.min(0, false)}")
+ println("Maximum:\n${dataset.max(0, false)}")
+
+ // now we can scale dataset with mean normalization
+ val datasetScaled = (dataset - mean) / std
+
+ // find out mean and std of scaled dataset
+
+ println("Mean of scaled:\n${datasetScaled.mean(0, false)}")
+ println("Mean of scaled:\n${datasetScaled.std(0, false)}")
+ }
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt
new file mode 100644
index 000000000..78370b517
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this 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.operations.invoke
+import space.kscience.kmath.tensors.core.DoubleTensor
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
+
+// solving linear system with LUP decomposition
+
+fun main () {
+
+ // work in context with linear operations
+ BroadcastDoubleTensorAlgebra {
+
+ // set true value of x
+ val trueX = fromArray(
+ intArrayOf(4),
+ doubleArrayOf(-2.0, 1.5, 6.8, -2.4)
+ )
+
+ // and A matrix
+ val a = fromArray(
+ intArrayOf(4, 4),
+ doubleArrayOf(
+ 0.5, 10.5, 4.5, 1.0,
+ 8.5, 0.9, 12.8, 0.1,
+ 5.56, 9.19, 7.62, 5.45,
+ 1.0, 2.0, -3.0, -2.5
+ )
+ )
+
+ // calculate y value
+ val b = a dot trueX
+
+ // check out A and b
+ println("A:\n$a")
+ println("b:\n$b")
+
+ // solve `Ax = b` system using LUP decomposition
+
+ // get P, L, U such that PA = LU
+ val (p, l, u) = a.lu()
+
+ // check that P is permutation matrix
+ println("P:\n$p")
+ // L is lower triangular matrix and U is upper triangular matrix
+ println("L:\n$l")
+ println("U:\n$u")
+ // and PA = LU
+ println("PA:\n${p dot a}")
+ println("LU:\n${l dot u}")
+
+ /* Ax = b;
+ PAx = Pb;
+ LUx = Pb;
+ let y = Ux, then
+ Ly = Pb -- this system can be easily solved, since the matrix L is lower triangular;
+ Ux = y can be solved the same way, since the matrix L is upper triangular
+ */
+
+
+
+ // this function returns solution x of a system lx = b, l should be lower triangular
+ fun solveLT(l: DoubleTensor, b: DoubleTensor): DoubleTensor {
+ val n = l.shape[0]
+ val x = zeros(intArrayOf(n))
+ for (i in 0 until n){
+ x[intArrayOf(i)] = (b[intArrayOf(i)] - l[i].dot(x).value()) / l[intArrayOf(i, i)]
+ }
+ return x
+ }
+
+ val y = solveLT(l, p dot b)
+
+ // solveLT(l, b) function can be easily adapted for upper triangular matrix by the permutation matrix revMat
+ // create it by placing ones on side diagonal
+ val revMat = u.zeroesLike()
+ val n = revMat.shape[0]
+ for (i in 0 until n) {
+ revMat[intArrayOf(i, n - 1 - i)] = 1.0
+ }
+
+ // solution of system ux = b, u should be upper triangular
+ fun solveUT(u: DoubleTensor, b: DoubleTensor): DoubleTensor = revMat dot solveLT(
+ revMat dot u dot revMat, revMat dot b
+ )
+
+ val x = solveUT(u, y)
+
+ println("True x:\n$trueX")
+ println("x founded with LU method:\n$x")
+ }
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt
new file mode 100644
index 000000000..5b3c2e1cd
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this 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.operations.invoke
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.DoubleTensor
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.toDoubleArray
+import kotlin.math.sqrt
+
+const val seed = 100500L
+
+// Simple feedforward neural network with backpropagation training
+
+// interface of network layer
+interface Layer {
+ fun forward(input: DoubleTensor): DoubleTensor
+ fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor
+}
+
+// activation layer
+open class Activation(
+ val activation: (DoubleTensor) -> DoubleTensor,
+ val activationDer: (DoubleTensor) -> DoubleTensor
+) : Layer {
+ override fun forward(input: DoubleTensor): DoubleTensor {
+ return activation(input)
+ }
+
+ override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor {
+ return DoubleTensorAlgebra { outputError * activationDer(input) }
+ }
+}
+
+fun relu(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
+ x.map { if (it > 0) it else 0.0 }
+}
+
+fun reluDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
+ x.map { if (it > 0) 1.0 else 0.0 }
+}
+
+// activation layer with relu activator
+class ReLU : Activation(::relu, ::reluDer)
+
+fun sigmoid(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
+ 1.0 / (1.0 + (-x).exp())
+}
+
+fun sigmoidDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
+ sigmoid(x) * (1.0 - sigmoid(x))
+}
+
+// activation layer with sigmoid activator
+class Sigmoid : Activation(::sigmoid, ::sigmoidDer)
+
+// dense layer
+class Dense(
+ private val inputUnits: Int,
+ private val outputUnits: Int,
+ private val learningRate: Double = 0.1
+) : Layer {
+
+ private val weights: DoubleTensor = DoubleTensorAlgebra {
+ randomNormal(
+ intArrayOf(inputUnits, outputUnits),
+ seed
+ ) * sqrt(2.0 / (inputUnits + outputUnits))
+ }
+
+ private val bias: DoubleTensor = DoubleTensorAlgebra { zeros(intArrayOf(outputUnits)) }
+
+ override fun forward(input: DoubleTensor): DoubleTensor {
+ return BroadcastDoubleTensorAlgebra { (input dot weights) + bias }
+ }
+
+ override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor = DoubleTensorAlgebra {
+ val gradInput = outputError dot weights.transpose()
+
+ val gradW = input.transpose() dot outputError
+ val gradBias = outputError.mean(dim = 0, keepDim = false) * input.shape[0].toDouble()
+
+ weights -= learningRate * gradW
+ bias -= learningRate * gradBias
+
+ gradInput
+ }
+
+}
+
+// simple accuracy equal to the proportion of correct answers
+fun accuracy(yPred: DoubleTensor, yTrue: DoubleTensor): Double {
+ check(yPred.shape contentEquals yTrue.shape)
+ val n = yPred.shape[0]
+ var correctCnt = 0
+ for (i in 0 until n) {
+ if (yPred[intArrayOf(i, 0)] == yTrue[intArrayOf(i, 0)]) {
+ correctCnt += 1
+ }
+ }
+ return correctCnt.toDouble() / n.toDouble()
+}
+
+// neural network class
+@OptIn(ExperimentalStdlibApi::class)
+class NeuralNetwork(private val layers: List) {
+ private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra {
+
+ val onesForAnswers = yPred.zeroesLike()
+ yTrue.toDoubleArray().forEachIndexed { index, labelDouble ->
+ val label = labelDouble.toInt()
+ onesForAnswers[intArrayOf(index, label)] = 1.0
+ }
+
+ val softmaxValue = yPred.exp() / yPred.exp().sum(dim = 1, keepDim = true)
+
+ (-onesForAnswers + softmaxValue) / (yPred.shape[0].toDouble())
+ }
+
+
+ private fun forward(x: DoubleTensor): List {
+ var input = x
+
+ return buildList {
+ layers.forEach { layer ->
+ val output = layer.forward(input)
+ add(output)
+ input = output
+ }
+ }
+ }
+
+ private fun train(xTrain: DoubleTensor, yTrain: DoubleTensor) {
+ val layerInputs = buildList {
+ add(xTrain)
+ addAll(forward(xTrain))
+ }
+
+ var lossGrad = softMaxLoss(layerInputs.last(), yTrain)
+
+ layers.zip(layerInputs).reversed().forEach { (layer, input) ->
+ lossGrad = layer.backward(input, lossGrad)
+ }
+ }
+
+ fun fit(xTrain: DoubleTensor, yTrain: DoubleTensor, batchSize: Int, epochs: Int) = DoubleTensorAlgebra {
+ fun iterBatch(x: DoubleTensor, y: DoubleTensor): Sequence> = sequence {
+ val n = x.shape[0]
+ val shuffledIndices = (0 until n).shuffled()
+ for (i in 0 until n step batchSize) {
+ val excerptIndices = shuffledIndices.drop(i).take(batchSize).toIntArray()
+ val batch = x.rowsByIndices(excerptIndices) to y.rowsByIndices(excerptIndices)
+ yield(batch)
+ }
+ }
+
+ for (epoch in 0 until epochs) {
+ println("Epoch ${epoch + 1}/$epochs")
+ for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) {
+ train(xBatch, yBatch)
+ }
+ println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true))}")
+ }
+ }
+
+ fun predict(x: DoubleTensor): DoubleTensor {
+ return forward(x).last()
+ }
+
+}
+
+
+@OptIn(ExperimentalStdlibApi::class)
+fun main() {
+ BroadcastDoubleTensorAlgebra {
+ val features = 5
+ val sampleSize = 250
+ val trainSize = 180
+ //val testSize = sampleSize - trainSize
+
+ // take sample of features from normal distribution
+ val x = randomNormal(intArrayOf(sampleSize, features), seed) * 2.5
+
+ x += fromArray(
+ intArrayOf(5),
+ doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // rows means
+ )
+
+
+ // define class like '1' if the sum of features > 0 and '0' otherwise
+ val y = fromArray(
+ intArrayOf(sampleSize, 1),
+ DoubleArray(sampleSize) { i ->
+ if (x[i].sum() > 0.0) {
+ 1.0
+ } else {
+ 0.0
+ }
+ }
+ )
+
+ // split train ans test
+ val trainIndices = (0 until trainSize).toList().toIntArray()
+ val testIndices = (trainSize until sampleSize).toList().toIntArray()
+
+ val xTrain = x.rowsByIndices(trainIndices)
+ val yTrain = y.rowsByIndices(trainIndices)
+
+ val xTest = x.rowsByIndices(testIndices)
+ val yTest = y.rowsByIndices(testIndices)
+
+ // build model
+ val layers = buildList {
+ add(Dense(features, 64))
+ add(ReLU())
+ add(Dense(64, 16))
+ add(ReLU())
+ add(Dense(16, 2))
+ add(Sigmoid())
+ }
+ val model = NeuralNetwork(layers)
+
+ // fit it with train data
+ model.fit(xTrain, yTrain, batchSize = 20, epochs = 10)
+
+ // make prediction
+ val prediction = model.predict(xTest)
+
+ // process raw prediction via argMax
+ val predictionLabels = prediction.argMax(1, true)
+
+ // find out accuracy
+ val acc = accuracy(yTest, predictionLabels)
+ println("Test accuracy:$acc")
+
+ }
+}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt
new file mode 100644
index 000000000..b42602988
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this 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.operations.invoke
+import space.kscience.kmath.tensors.core.DoubleTensor
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
+
+import kotlin.math.abs
+
+// OLS estimator using SVD
+
+fun main() {
+ //seed for random
+ val randSeed = 100500L
+
+ // work in context with linear operations
+ DoubleTensorAlgebra {
+ // take coefficient vector from normal distribution
+ val alpha = randomNormal(
+ intArrayOf(5),
+ randSeed
+ ) + fromArray(
+ intArrayOf(5),
+ doubleArrayOf(1.0, 2.5, 3.4, 5.0, 10.1)
+ )
+
+ println("Real alpha:\n$alpha")
+
+ // also take sample of size 20 from normal distribution for x
+ val x = randomNormal(
+ intArrayOf(20, 5),
+ randSeed
+ )
+
+ // calculate y and add gaussian noise (N(0, 0.05))
+ val y = x dot alpha
+ y += y.randomNormalLike(randSeed) * 0.05
+
+ // now restore the coefficient vector with OSL estimator with SVD
+ val (u, singValues, v) = x.svd()
+
+ // we have to make sure the singular values of the matrix are not close to zero
+ println("Singular values:\n$singValues")
+
+
+ // inverse Sigma matrix can be restored from singular values with diagonalEmbedding function
+ val sigma = diagonalEmbedding(singValues.map{ if (abs(it) < 1e-3) 0.0 else 1.0/it })
+
+ val alphaOLS = v dot sigma dot u.transpose() dot y
+ println("Estimated alpha:\n" +
+ "$alphaOLS")
+
+ // figure out MSE of approximation
+ fun mse(yTrue: DoubleTensor, yPred: DoubleTensor): Double {
+ require(yTrue.shape.size == 1)
+ require(yTrue.shape contentEquals yPred.shape)
+
+ val diff = yTrue - yPred
+ return diff.dot(diff).sqrt().value()
+ }
+
+ println("MSE: ${mse(alpha, alphaOLS)}")
+ }
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt
new file mode 100644
index 000000000..f8ac13d3f
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this 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.operations.invoke
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
+
+
+// simple PCA
+
+fun main(){
+ val seed = 100500L
+
+ // work in context with broadcast methods
+ BroadcastDoubleTensorAlgebra {
+
+ // assume x is range from 0 until 10
+ val x = fromArray(
+ intArrayOf(10),
+ (0 until 10).toList().map { it.toDouble() }.toDoubleArray()
+ )
+
+ // take y dependent on x with noise
+ val y = 2.0 * x + (3.0 + x.randomNormalLike(seed) * 1.5)
+
+ println("x:\n$x")
+ println("y:\n$y")
+
+ // stack them into single dataset
+ val dataset = stack(listOf(x, y)).transpose()
+
+ // normalize both x and y
+ val xMean = x.mean()
+ val yMean = y.mean()
+
+ val xStd = x.std()
+ val yStd = y.std()
+
+ val xScaled = (x - xMean) / xStd
+ val yScaled = (y - yMean) / yStd
+
+ // save means ans standard deviations for further recovery
+ val mean = fromArray(
+ intArrayOf(2),
+ doubleArrayOf(xMean, yMean)
+ )
+ println("Means:\n$mean")
+
+ val std = fromArray(
+ intArrayOf(2),
+ doubleArrayOf(xStd, yStd)
+ )
+ println("Standard deviations:\n$std")
+
+ // calculate the covariance matrix of scaled x and y
+ val covMatrix = cov(listOf(xScaled, yScaled))
+ println("Covariance matrix:\n$covMatrix")
+
+ // and find out eigenvector of it
+ val (_, evecs) = covMatrix.symEig()
+ val v = evecs[0]
+ println("Eigenvector:\n$v")
+
+ // reduce dimension of dataset
+ val datasetReduced = v dot stack(listOf(xScaled, yScaled))
+ println("Reduced data:\n$datasetReduced")
+
+ // we can restore original data from reduced data.
+ // for example, find 7th element of dataset
+ val n = 7
+ val restored = (datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean
+ println("Original value:\n${dataset[n]}")
+ println("Restored value:\n$restored")
+ }
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 442d9132e..f371643ee 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 6ad9eb930..4f906e0c8 100755
--- a/gradlew
+++ b/gradlew
@@ -1,8 +1,19 @@
#!/usr/bin/env sh
#
-# Copyright 2018-2021 KMath contributors.
-# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
##############################################################################
diff --git a/kmath-ast/README.md b/kmath-ast/README.md
index b1ef9c7d3..646ab4306 100644
--- a/kmath-ast/README.md
+++ b/kmath-ast/README.md
@@ -1,41 +1,37 @@
# Module kmath-ast
-Abstract syntax tree expression representation and related optimizations.
+Performance and visualization extensions to MST API.
- - [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
- - [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
- - [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
- - [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
+ - [expression-language](src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
- [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
- [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
+ - [rendering](src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering
## Artifact:
-The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-6`.
+The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-8`.
**Gradle:**
```gradle
repositories {
maven { url 'https://repo.kotlin.link' }
- maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
- maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
+ mavenCentral()
}
dependencies {
- implementation 'space.kscience:kmath-ast:0.3.0-dev-6'
+ implementation 'space.kscience:kmath-ast:0.3.0-dev-8'
}
```
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
- maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
- maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
+ mavenCentral()
}
dependencies {
- implementation("space.kscience:kmath-ast:0.3.0-dev-6")
+ implementation("space.kscience:kmath-ast:0.3.0-dev-8")
}
```
@@ -43,21 +39,26 @@ dependencies {
### On JVM
-`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds
-a special implementation of `Expression` with implemented `invoke` function.
+`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a
+special implementation of `Expression` with implemented `invoke` function.
For example, the following builder:
```kotlin
-DoubleField.mstInField { symbol("x") + 2 }.compile()
+import space.kscience.kmath.expressions.*
+import space.kscience.kmath.operations.*
+import space.kscience.kmath.asm.*
+
+MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
-… leads to generation of bytecode, which can be decompiled to the following Java class:
+... leads to generation of bytecode, which can be decompiled to the following Java class:
```java
package space.kscience.kmath.asm.generated;
import java.util.Map;
+
import kotlin.jvm.functions.Function2;
import space.kscience.kmath.asm.internal.MapIntrinsics;
import space.kscience.kmath.expressions.Expression;
@@ -67,7 +68,7 @@ public final class AsmCompiledExpression_45045_0 implements Expression {
private final Object[] constants;
public final Double invoke(Map arguments) {
- return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2);
+ return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2);
}
public AsmCompiledExpression_45045_0(Object[] constants) {
@@ -77,19 +78,10 @@ public final class AsmCompiledExpression_45045_0 implements Expression {
```
-### Example Usage
-
-This API extends MST and MstExpression, so you may optimize as both of them:
-
-```kotlin
-DoubleField.mstInField { symbol("x") + 2 }.compile()
-DoubleField.expression("x+2".parseMath())
-```
-
#### Known issues
-- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
- class loading overhead.
+- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class
+ loading overhead.
- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders.
### On JS
@@ -97,33 +89,62 @@ DoubleField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
-DoubleField.mstInField { symbol("x") + 2 }.compile()
+import space.kscience.kmath.expressions.*
+import space.kscience.kmath.operations.*
+import space.kscience.kmath.estree.*
+
+MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
The code above returns expression implemented with such a JS function:
```js
var executable = function (constants, arguments) {
- return constants[1](constants[0](arguments, "x"), 2);
+ return constants[1](constants[0](arguments, "x"), 2);
};
```
+JS also supports very experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation.
+Currently, only expressions inside `DoubleField` and `IntRing` are supported.
+
+```kotlin
+import space.kscience.kmath.expressions.*
+import space.kscience.kmath.operations.*
+import space.kscience.kmath.wasm.*
+
+MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
+```
+
+An example of emitted Wasm IR in the form of WAT:
+
+```lisp
+(func $executable (param $0 f64) (result f64)
+ (f64.add
+ (local.get $0)
+ (f64.const 2)
+ )
+)
+```
+
#### Known issues
-- This feature uses `eval` which can be unavailable in several environments.
+- ESTree expression compilation uses `eval` which can be unavailable in several environments.
+- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).
## Rendering expressions
-kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
+kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
Example usage:
```kotlin
import space.kscience.kmath.ast.*
import space.kscience.kmath.ast.rendering.*
+import space.kscience.kmath.misc.*
+@OptIn(UnstableKMathAPI::class)
public fun main() {
- val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
+ val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(12)+x^(2/3)".parseMath()
val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
println("LaTeX:")
@@ -135,15 +156,80 @@ public fun main() {
}
```
-Result LaTeX:
+Result LaTeX:
-![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D)
+![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3})
-Result MathML (embedding MathML is not allowed by GitHub Markdown):
+Result MathML (can be used with MathJax or other renderers):
+
+
```html
-ex-sin-12x2×1010+x3-12
+
```
-It is also possible to create custom algorithms of render, and even add support of other markup languages
+
+
+It is also possible to create custom algorithms of render, and even add support of other markup languages
(see API reference).
diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts
index 3f309b67c..508374d82 100644
--- a/kmath-ast/build.gradle.kts
+++ b/kmath-ast/build.gradle.kts
@@ -1,10 +1,3 @@
-/*
- * Copyright 2018-2021 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-import ru.mipt.npm.gradle.Maturity
-
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
@@ -25,8 +18,13 @@ kotlin.js {
}
kotlin.sourceSets {
+ filter { it.name.contains("test", true) }
+ .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings)
+ .forEach { it.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") }
+
commonMain {
dependencies {
+ api("com.github.h0tk3y.betterParse:better-parse:0.4.2")
api(project(":kmath-core"))
}
}
@@ -39,13 +37,15 @@ kotlin.sourceSets {
jsMain {
dependencies {
- implementation(npm("astring", "1.7.0"))
+ implementation(npm("astring", "1.7.4"))
+ implementation(npm("binaryen", "100.0"))
+ implementation(npm("js-base64", "3.6.0"))
+ implementation(npm("webassembly", "0.11.0"))
}
}
jvmMain {
dependencies {
- api("com.github.h0tk3y.betterParse:better-parse:0.4.1")
implementation("org.ow2.asm:asm:9.1")
implementation("org.ow2.asm:asm-commons:9.1")
}
@@ -58,31 +58,13 @@ tasks.dokkaHtml {
}
readme {
- maturity = Maturity.PROTOTYPE
+ maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(
id = "expression-language",
description = "Expression language and its parser",
- ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt"
- )
-
- feature(
- id = "mst",
- description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
- ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
- )
-
- feature(
- id = "mst-building",
- description = "MST building algebraic structure",
- ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt"
- )
-
- feature(
- id = "mst-interpreter",
- description = "MST interpreter",
- ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
+ ref = "src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt"
)
feature(
@@ -96,4 +78,10 @@ readme {
description = "Dynamic MST to JS compiler",
ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt"
)
+
+ feature(
+ id = "rendering",
+ description = "Extendable MST rendering",
+ ref = "src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt"
+ )
}
diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md
index 9ed44d584..80ea31642 100644
--- a/kmath-ast/docs/README-TEMPLATE.md
+++ b/kmath-ast/docs/README-TEMPLATE.md
@@ -1,6 +1,6 @@
# Module kmath-ast
-Abstract syntax tree expression representation and related optimizations.
+Performance and visualization extensions to MST API.
${features}
@@ -10,21 +10,26 @@ ${artifact}
### On JVM
-`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds
-a special implementation of `Expression` with implemented `invoke` function.
+`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a
+special implementation of `Expression` with implemented `invoke` function.
For example, the following builder:
```kotlin
-DoubleField.mstInField { symbol("x") + 2 }.compile()
+import space.kscience.kmath.expressions.*
+import space.kscience.kmath.operations.*
+import space.kscience.kmath.asm.*
+
+MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
-… leads to generation of bytecode, which can be decompiled to the following Java class:
+... leads to generation of bytecode, which can be decompiled to the following Java class:
```java
package space.kscience.kmath.asm.generated;
import java.util.Map;
+
import kotlin.jvm.functions.Function2;
import space.kscience.kmath.asm.internal.MapIntrinsics;
import space.kscience.kmath.expressions.Expression;
@@ -34,7 +39,7 @@ public final class AsmCompiledExpression_45045_0 implements Expression {
private final Object[] constants;
public final Double invoke(Map arguments) {
- return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2);
+ return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2);
}
public AsmCompiledExpression_45045_0(Object[] constants) {
@@ -44,19 +49,10 @@ public final class AsmCompiledExpression_45045_0 implements Expression {
```
-### Example Usage
-
-This API extends MST and MstExpression, so you may optimize as both of them:
-
-```kotlin
-DoubleField.mstInField { symbol("x") + 2 }.compile()
-DoubleField.expression("x+2".parseMath())
-```
-
#### Known issues
-- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
- class loading overhead.
+- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class
+ loading overhead.
- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders.
### On JS
@@ -64,33 +60,62 @@ DoubleField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
-DoubleField.mstInField { symbol("x") + 2 }.compile()
+import space.kscience.kmath.expressions.*
+import space.kscience.kmath.operations.*
+import space.kscience.kmath.estree.*
+
+MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
The code above returns expression implemented with such a JS function:
```js
var executable = function (constants, arguments) {
- return constants[1](constants[0](arguments, "x"), 2);
+ return constants[1](constants[0](arguments, "x"), 2);
};
```
+JS also supports very experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation.
+Currently, only expressions inside `DoubleField` and `IntRing` are supported.
+
+```kotlin
+import space.kscience.kmath.expressions.*
+import space.kscience.kmath.operations.*
+import space.kscience.kmath.wasm.*
+
+MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
+```
+
+An example of emitted Wasm IR in the form of WAT:
+
+```lisp
+(func \$executable (param \$0 f64) (result f64)
+ (f64.add
+ (local.get \$0)
+ (f64.const 2)
+ )
+)
+```
+
#### Known issues
-- This feature uses `eval` which can be unavailable in several environments.
+- ESTree expression compilation uses `eval` which can be unavailable in several environments.
+- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).
## Rendering expressions
-kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
+kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
Example usage:
```kotlin
import space.kscience.kmath.ast.*
import space.kscience.kmath.ast.rendering.*
+import space.kscience.kmath.misc.*
+@OptIn(UnstableKMathAPI::class)
public fun main() {
- val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
+ val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(12)+x^(2/3)".parseMath()
val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
println("LaTeX:")
@@ -102,15 +127,80 @@ public fun main() {
}
```
-Result LaTeX:
+Result LaTeX:
-![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D)
+![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3})
-Result MathML (embedding MathML is not allowed by GitHub Markdown):
+Result MathML (can be used with MathJax or other renderers):
+
+
```html
-ex-sin-12x2×1010+x3-12
+
```
-It is also possible to create custom algorithms of render, and even add support of other markup languages
+
+
+It is also possible to create custom algorithms of render, and even add support of other markup languages
(see API reference).
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt
similarity index 96%
rename from kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt
rename to kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt
index 025f4984c..246625d29 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt
@@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
-// TODO move to common when https://github.com/h0tk3y/better-parse/pull/37 is merged
-
package space.kscience.kmath.ast
import com.github.h0tk3y.betterParse.combinators.*
@@ -31,7 +29,6 @@ import space.kscience.kmath.operations.RingOperations
* @author Iaroslav Postovalov
*/
public object ArithmeticsEvaluator : Grammar() {
- // TODO replace with "...".toRegex() when better-parse 0.4.1 is released
private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?".toRegex())
private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*".toRegex())
private val lpar: Token by literalToken("(")
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt
index 34230f3c8..01717b0f9 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt
@@ -5,6 +5,8 @@
package space.kscience.kmath.ast.rendering
+import space.kscience.kmath.misc.UnstableKMathAPI
+
/**
* [SyntaxRenderer] implementation for LaTeX.
*
@@ -23,6 +25,7 @@ package space.kscience.kmath.ast.rendering
*
* @author Iaroslav Postovalov
*/
+@UnstableKMathAPI
public object LatexSyntaxRenderer : SyntaxRenderer {
public override fun render(node: MathSyntax, output: Appendable): Unit = output.run {
fun render(syntax: MathSyntax) = render(syntax, output)
@@ -71,6 +74,15 @@ public object LatexSyntaxRenderer : SyntaxRenderer {
append('}')
}
+ is ExponentSyntax -> if (node.useOperatorForm) {
+ append("\\operatorname{exp}\\,")
+ render(node.operand)
+ } else {
+ append("e^{")
+ render(node.operand)
+ append('}')
+ }
+
is SuperscriptSyntax -> {
render(node.left)
append("^{")
@@ -106,7 +118,11 @@ public object LatexSyntaxRenderer : SyntaxRenderer {
render(node.right)
}
- is FractionSyntax -> {
+ is FractionSyntax -> if (node.infix) {
+ render(node.left)
+ append('/')
+ render(node.right)
+ } else {
append("\\frac{")
render(node.left)
append("}{")
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt
index f7487a356..cda8e2322 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt
@@ -5,6 +5,8 @@
package space.kscience.kmath.ast.rendering
+import space.kscience.kmath.misc.UnstableKMathAPI
+
/**
* [SyntaxRenderer] implementation for MathML.
*
@@ -12,14 +14,18 @@ package space.kscience.kmath.ast.rendering
*
* @author Iaroslav Postovalov
*/
+@UnstableKMathAPI
public object MathMLSyntaxRenderer : SyntaxRenderer {
public override fun render(node: MathSyntax, output: Appendable) {
- output.append("