v0.3.0-dev-18 #459

Merged
altavir merged 64 commits from dev into master 2022-02-13 17:50:34 +03:00
409 changed files with 8093 additions and 2517 deletions

5
.gitignore vendored
View File

@ -4,8 +4,6 @@ out/
.idea/ .idea/
!.idea/copyright/
!.idea/scopes/
.vscode/ .vscode/
@ -18,3 +16,6 @@ out/
# Generated by javac -h and runtime # Generated by javac -h and runtime
*.class *.class
*.log *.log
!/.idea/copyright/
!/.idea/scopes/

View File

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright 2018-2021 KMath contributors.&#10;Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file." />
<option name="myName" value="kmath" />
</copyright>
</component>

View File

@ -0,0 +1,21 @@
<component name="CopyrightManager">
<settings default="kmath">
<module2copyright>
<element module="Apply copyright" copyright="kmath" />
</module2copyright>
<LanguageOptions name="Groovy">
<option name="fileTypeOverride" value="1" />
</LanguageOptions>
<LanguageOptions name="HTML">
<option name="fileTypeOverride" value="1" />
<option name="prefixLines" value="false" />
</LanguageOptions>
<LanguageOptions name="Properties">
<option name="fileTypeOverride" value="1" />
</LanguageOptions>
<LanguageOptions name="XML">
<option name="fileTypeOverride" value="1" />
<option name="prefixLines" value="false" />
</LanguageOptions>
</settings>
</component>

View File

@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="Apply copyright" pattern="!file[*]:*//testData//*&amp;&amp;!file[*]:testData//*&amp;&amp;!file[*]:*.gradle.kts&amp;&amp;!file[*]:*.gradle&amp;&amp;!file[group:kotlin-ultimate]:*/&amp;&amp;!file[kotlin.libraries]:stdlib/api//*" />
</component>

View File

@ -17,6 +17,8 @@
- `BigInt` operation performance improvement and fixes by @zhelenskiy (#328) - `BigInt` operation performance improvement and fixes by @zhelenskiy (#328)
- Integration between `MST` and Symja `IExpr` - Integration between `MST` and Symja `IExpr`
- Complex power - Complex power
- Separate methods for UInt, Int and Number powers. NaN safety.
- Tensorflow prototype
### Changed ### Changed
- Exponential operations merged with hyperbolic functions - Exponential operations merged with hyperbolic functions
@ -45,6 +47,7 @@
- Buffer algebra does not require size anymore - Buffer algebra does not require size anymore
- Operations -> Ops - Operations -> Ops
- Default Buffer and ND algebras are now Ops and lack neutral elements (0, 1) as well as algebra-level shapes. - Default Buffer and ND algebras are now Ops and lack neutral elements (0, 1) as well as algebra-level shapes.
- Tensor algebra takes read-only structures as input and inherits AlgebraND
### Deprecated ### Deprecated
- Specialized `DoubleBufferAlgebra` - Specialized `DoubleBufferAlgebra`

View File

@ -50,35 +50,6 @@ module definitions below. The module stability could have the following levels:
with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool.
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
<!--Current feature list is [here](/docs/features.md)-->
<!--* **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).-->
<!--* **Histograms** Fast multi-dimensional histograms.-->
<!--* **Streaming** Streaming operations on mathematical objects and objects buffers.-->
<!--* **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 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.-->
<!--* **Array statistics** -->
<!--* **Integration** Univariate and multivariate integration framework.-->
<!--* **Probability and distributions**-->
<!--* **Fitting** Non-linear curve fitting facilities-->
## Modules ## Modules
<hr/> <hr/>
@ -240,6 +211,12 @@ One can still use generic algebras though.
> **Maturity**: DEVELOPMENT > **Maturity**: DEVELOPMENT
<hr/> <hr/>
* ### [kmath-multik](kmath-multik)
>
>
> **Maturity**: PROTOTYPE
<hr/>
* ### [kmath-nd4j](kmath-nd4j) * ### [kmath-nd4j](kmath-nd4j)
> >
> >
@ -252,6 +229,12 @@ One can still use generic algebras though.
<hr/> <hr/>
* ### [kmath-optimization](kmath-optimization)
>
>
> **Maturity**: EXPERIMENTAL
<hr/>
* ### [kmath-stat](kmath-stat) * ### [kmath-stat](kmath-stat)
> >
> >
@ -264,6 +247,12 @@ One can still use generic algebras though.
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
<hr/> <hr/>
* ### [kmath-tensorflow](kmath-tensorflow)
>
>
> **Maturity**: PROTOTYPE
<hr/>
* ### [kmath-tensors](kmath-tensors) * ### [kmath-tensors](kmath-tensors)
> >
> >
@ -319,8 +308,8 @@ repositories {
} }
dependencies { dependencies {
api("space.kscience:kmath-core:0.3.0-dev-14") api("space.kscience:kmath-core:0.3.0-dev-17")
// api("space.kscience:kmath-core-jvm:0.3.0-dev-14") for jvm-specific version // api("space.kscience:kmath-core-jvm:0.3.0-dev-17") for jvm-specific version
} }
``` ```

View File

@ -13,19 +13,22 @@ sourceSets.register("benchmarks")
repositories { repositories {
mavenCentral() 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 { kotlin {
jvm() jvm()
js(IR) {
nodejs()
}
sourceSets { sourceSets {
all {
languageSettings {
progressiveMode = true
}
}
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {
implementation(project(":kmath-ast")) implementation(project(":kmath-ast"))
@ -35,9 +38,8 @@ kotlin {
implementation(project(":kmath-stat")) implementation(project(":kmath-stat"))
implementation(project(":kmath-dimensions")) implementation(project(":kmath-dimensions"))
implementation(project(":kmath-for-real")) implementation(project(":kmath-for-real"))
implementation(project(":kmath-jafama"))
implementation(project(":kmath-tensors")) implementation(project(":kmath-tensors"))
implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.1") implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.4.2")
} }
} }
@ -48,7 +50,8 @@ kotlin {
implementation(project(":kmath-nd4j")) implementation(project(":kmath-nd4j"))
implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-kotlingrad"))
implementation(project(":kmath-viktor")) implementation(project(":kmath-viktor"))
implementation(projects.kmathMultik) implementation(project(":kmath-jafama"))
implementation(project(":kmath-multik"))
implementation("org.nd4j:nd4j-native:1.0.0-M1") implementation("org.nd4j:nd4j-native:1.0.0-M1")
// uncomment if your system supports AVX2 // uncomment if your system supports AVX2
// val os = System.getProperty("os.name") // val os = System.getProperty("os.name")
@ -69,12 +72,13 @@ benchmark {
// Setup configurations // Setup configurations
targets { targets {
register("jvm") register("jvm")
register("js")
} }
fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() { fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() {
warmups = 1 warmups = 2
iterations = 5 iterations = 5
iterationTime = 1000 iterationTime = 2000
iterationTimeUnit = "ms" iterationTimeUnit = "ms"
} }
@ -94,7 +98,12 @@ benchmark {
} }
configurations.register("expressions") { configurations.register("expressions") {
commonConfiguration() // Some extra precision
warmups = 2
iterations = 10
iterationTime = 10
iterationTimeUnit = "s"
outputTimeUnit = "s"
include("ExpressionsInterpretersBenchmark") include("ExpressionsInterpretersBenchmark")
} }
@ -131,23 +140,21 @@ afterEvaluate {
} }
} }
kotlin.sourceSets.all { kotlin.sourceSets.all {
with(languageSettings) { with(languageSettings) {
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") optIn("kotlin.contracts.ExperimentalContracts")
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") optIn("kotlin.ExperimentalUnsignedTypes")
useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") optIn("space.kscience.kmath.misc.UnstableKMathAPI")
} }
} }
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> { tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xlambdas=indy"
} }
} }
readme { readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
} }

View File

@ -0,0 +1,105 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this 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.expressions.*
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.math.sin
import kotlin.random.Random
import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression
import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression
@State(Scope.Benchmark)
class ExpressionsInterpretersBenchmark {
/**
* Benchmark case for [Expression] created with [expressionInExtendedField].
*/
@Benchmark
fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, blackhole)
/**
* Benchmark case for [Expression] created with [toExpression].
*/
@Benchmark
fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, blackhole)
/**
* Benchmark case for [Expression] created with [compileToExpression].
*/
@Benchmark
fun wasmExpression(blackhole: Blackhole) = invokeAndSum(wasm, blackhole)
/**
* Benchmark case for [Expression] created with [compileToExpression].
*/
@Benchmark
fun estreeExpression(blackhole: Blackhole) = invokeAndSum(estree, blackhole)
/**
* Benchmark case for [Expression] implemented manually with `kotlin.math` functions.
*/
@Benchmark
fun rawExpression(blackhole: Blackhole) = invokeAndSum(raw, blackhole)
/**
* Benchmark case for direct computation w/o [Expression].
*/
@Benchmark
fun justCalculate(blackhole: Blackhole) {
val random = Random(0)
var sum = 0.0
repeat(times) {
val x = random.nextDouble()
sum += x * 2.0 + 2.0 / x - 16.0 / sin(x)
}
blackhole.consume(sum)
}
private fun invokeAndSum(expr: Expression<Double>, blackhole: Blackhole) {
val random = Random(0)
var sum = 0.0
val m = HashMap<Symbol, Double>()
repeat(times) {
m[x] = random.nextDouble()
sum += expr(m)
}
blackhole.consume(sum)
}
private companion object {
private val x by symbol
private const val times = 1_000_000
private val functional = DoubleField.expression {
val x = bindSymbol(Symbol.x)
x * number(2.0) + 2.0 / x - 16.0 / sin(x)
}
private val node = MstExtendedField {
x * 2.0 + number(2.0) / x - number(16.0) / sin(x)
}
private val mst = node.toExpression(DoubleField)
private val wasm = node.wasmCompileToExpression(DoubleField)
private val estree = node.estreeCompileToExpression(DoubleField)
private val raw = Expression<Double> { args ->
val x = args[x]!!
x * 2.0 + 2.0 / x - 16.0 / sin(x)
}
}
}

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks
@ -13,6 +13,7 @@ import space.kscience.kmath.commons.linear.CMLinearSpace
import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.invoke
import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.linearSpace
import space.kscience.kmath.multik.multikAlgebra
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import kotlin.random.Random import kotlin.random.Random
@ -58,6 +59,16 @@ internal class DotBenchmark {
blackhole.consume(matrix1 dot matrix2) blackhole.consume(matrix1 dot matrix2)
} }
// @Benchmark
// fun tensorDot(blackhole: Blackhole) = with(Double.tensorAlgebra) {
// blackhole.consume(matrix1 dot matrix2)
// }
@Benchmark
fun multikDot(blackhole: Blackhole) = with(Double.multikAlgebra) {
blackhole.consume(matrix1 dot matrix2)
}
@Benchmark @Benchmark
fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace(Buffer.Companion::auto)) { fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace(Buffer.Companion::auto)) {
blackhole.consume(matrix1 dot matrix2) blackhole.consume(matrix1 dot matrix2)

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks
@ -11,6 +11,7 @@ import kotlinx.benchmark.Scope
import kotlinx.benchmark.State import kotlinx.benchmark.State
import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.expressions.* import space.kscience.kmath.expressions.*
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
@ -35,7 +36,30 @@ internal class ExpressionsInterpretersBenchmark {
* Benchmark case for [Expression] created with [compileToExpression]. * Benchmark case for [Expression] created with [compileToExpression].
*/ */
@Benchmark @Benchmark
fun asmExpression(blackhole: Blackhole) = invokeAndSum(asm, blackhole) fun asmGenericExpression(blackhole: Blackhole) = invokeAndSum(asmGeneric, blackhole)
/**
* Benchmark case for [Expression] created with [compileToExpression].
*/
@Benchmark
fun asmPrimitiveExpressionArray(blackhole: Blackhole) {
val random = Random(0)
var sum = 0.0
val m = DoubleArray(1)
repeat(times) {
m[xIdx] = random.nextDouble()
sum += asmPrimitive(m)
}
blackhole.consume(sum)
}
/**
* Benchmark case for [Expression] created with [compileToExpression].
*/
@Benchmark
fun asmPrimitiveExpression(blackhole: Blackhole) = invokeAndSum(asmPrimitive, blackhole)
/** /**
* Benchmark case for [Expression] implemented manually with `kotlin.math` functions. * Benchmark case for [Expression] implemented manually with `kotlin.math` functions.
@ -62,9 +86,11 @@ internal class ExpressionsInterpretersBenchmark {
private fun invokeAndSum(expr: Expression<Double>, blackhole: Blackhole) { private fun invokeAndSum(expr: Expression<Double>, blackhole: Blackhole) {
val random = Random(0) val random = Random(0)
var sum = 0.0 var sum = 0.0
val m = HashMap<Symbol, Double>()
repeat(times) { repeat(times) {
sum += expr(x to random.nextDouble()) m[x] = random.nextDouble()
sum += expr(m)
} }
blackhole.consume(sum) blackhole.consume(sum)
@ -72,7 +98,6 @@ internal class ExpressionsInterpretersBenchmark {
private companion object { private companion object {
private val x by symbol private val x by symbol
private val algebra = DoubleField
private const val times = 1_000_000 private const val times = 1_000_000
private val functional = DoubleField.expression { private val functional = DoubleField.expression {
@ -85,7 +110,11 @@ internal class ExpressionsInterpretersBenchmark {
} }
private val mst = node.toExpression(DoubleField) private val mst = node.toExpression(DoubleField)
private val asm = node.compileToExpression(DoubleField)
private val asmPrimitive = node.compileToExpression(DoubleField)
private val xIdx = asmPrimitive.indexer.indexOf(x)
private val asmGeneric = node.compileToExpression(DoubleField as Algebra<Double>)
private val raw = Expression<Double> { args -> private val raw = Expression<Double> { args ->
val x = args[x]!! val x = args[x]!!

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks
@ -13,8 +13,7 @@ import org.jetbrains.kotlinx.multik.api.Multik
import org.jetbrains.kotlinx.multik.api.ones import org.jetbrains.kotlinx.multik.api.ones
import org.jetbrains.kotlinx.multik.ndarray.data.DN import org.jetbrains.kotlinx.multik.ndarray.data.DN
import org.jetbrains.kotlinx.multik.ndarray.data.DataType import org.jetbrains.kotlinx.multik.ndarray.data.DataType
import space.kscience.kmath.multik.multikND import space.kscience.kmath.multik.multikAlgebra
import space.kscience.kmath.multik.multikTensorAlgebra
import space.kscience.kmath.nd.BufferedFieldOpsND import space.kscience.kmath.nd.BufferedFieldOpsND
import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd.ndAlgebra
@ -79,7 +78,7 @@ internal class NDFieldBenchmark {
} }
@Benchmark @Benchmark
fun multikInPlaceAdd(blackhole: Blackhole) = with(DoubleField.multikTensorAlgebra) { fun multikInPlaceAdd(blackhole: Blackhole) = with(DoubleField.multikAlgebra) {
val res = Multik.ones<Double, DN>(shape, DataType.DoubleDataType).wrap() val res = Multik.ones<Double, DN>(shape, DataType.DoubleDataType).wrap()
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
blackhole.consume(res) blackhole.consume(res)
@ -100,7 +99,7 @@ internal class NDFieldBenchmark {
private val specializedField = DoubleField.ndAlgebra private val specializedField = DoubleField.ndAlgebra
private val genericField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) private val genericField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing)
private val nd4jField = DoubleField.nd4j private val nd4jField = DoubleField.nd4j
private val multikField = DoubleField.multikND private val multikField = DoubleField.multikAlgebra
private val viktorField = DoubleField.viktorAlgebra private val viktorField = DoubleField.viktorAlgebra
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks

View File

@ -1,31 +1,22 @@
import java.net.URL
plugins { plugins {
id("ru.mipt.npm.gradle.project") id("ru.mipt.npm.gradle.project")
kotlin("jupyter.api") apply false id("org.jetbrains.kotlinx.kover") version "0.5.0-RC"
} }
allprojects { allprojects {
repositories { repositories {
maven("https://clojars.org/repo")
maven("https://jitpack.io")
maven("http://logicrunch.research.it.uu.se/maven") {
isAllowInsecureProtocol = true
}
maven("https://oss.sonatype.org/content/repositories/snapshots") maven("https://oss.sonatype.org/content/repositories/snapshots")
mavenCentral() mavenCentral()
} }
group = "space.kscience" group = "space.kscience"
version = "0.3.0-dev-17" version = "0.3.0-dev-18"
} }
subprojects { subprojects {
if (name.startsWith("kmath")) apply<MavenPublishPlugin>() if (name.startsWith("kmath")) apply<MavenPublishPlugin>()
afterEvaluate { plugins.withId("org.jetbrains.dokka"){
tasks.withType<org.jetbrains.dokka.gradle.DokkaTaskPartial> { tasks.withType<org.jetbrains.dokka.gradle.DokkaTaskPartial> {
dependsOn(tasks["assemble"]) dependsOn(tasks["assemble"])
@ -39,7 +30,7 @@ subprojects {
localDirectory.set(kotlinDir) localDirectory.set(kotlinDir)
remoteUrl.set( remoteUrl.set(
URL("https://github.com/mipt-npm/${rootProject.name}/tree/master/${this@subprojects.name}/$kotlinDirPath") java.net.URL("https://github.com/mipt-npm/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath")
) )
} }
@ -64,9 +55,9 @@ subprojects {
readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md")
ksciencePublish { ksciencePublish {
vcs("https://github.com/mipt-npm/kmath") github("kmath")
space(publish = true) space()
sonatype(publish = true) sonatype()
} }
apiValidation.nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") apiValidation.nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI")

View File

@ -1,20 +1,30 @@
plugins { plugins {
`kotlin-dsl` `kotlin-dsl`
kotlin("plugin.serialization") version "1.4.31" `version-catalog`
alias(npmlibs.plugins.kotlin.plugin.serialization)
} }
java.targetCompatibility = JavaVersion.VERSION_11
repositories { repositories {
maven("https://repo.kotlin.link") maven("https://repo.kotlin.link")
mavenCentral() mavenCentral()
gradlePluginPortal() gradlePluginPortal()
} }
val toolsVersion: String by extra
val kotlinVersion = npmlibs.versions.kotlin.asProvider().get()
val benchmarksVersion = "0.4.2"
dependencies { dependencies {
api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") api("ru.mipt.npm:gradle-tools:$toolsVersion")
api("ru.mipt.npm:gradle-tools:0.10.2") //plugins form benchmarks
api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.3.1") api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion")
api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
//to be used inside build-script only
implementation(npmlibs.kotlinx.serialization.json)
} }
kotlin.sourceSets.all { kotlin.sourceSets.all {
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalStdlibApi") languageSettings.optIn("kotlin.OptIn")
} }

View File

@ -0,0 +1,14 @@
#
# Copyright 2018-2021 KMath contributors.
# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
#
kotlin.code.style=official
kotlin.mpp.stability.nowarn=true
kotlin.jupyter.add.scanner=false
org.gradle.configureondemand=true
org.gradle.parallel=true
toolsVersion=0.10.9-kotlin-1.6.10

View File

@ -0,0 +1,24 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
enableFeaturePreview("VERSION_CATALOGS")
dependencyResolutionManagement {
val toolsVersion: String by extra
repositories {
maven("https://repo.kotlin.link")
mavenCentral()
}
versionCatalogs {
create("npmlibs") {
from("ru.mipt.npm:version-catalog:$toolsVersion")
}
}
}

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks

View File

@ -1,17 +1,20 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.benchmarks
import kotlinx.benchmark.gradle.BenchmarksExtension import kotlinx.benchmark.gradle.BenchmarksExtension
import kotlinx.serialization.* import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.* import kotlinx.serialization.json.Json
import org.gradle.api.Project import org.gradle.api.Project
import ru.mipt.npm.gradle.KScienceReadmeExtension import ru.mipt.npm.gradle.KScienceReadmeExtension
import java.time.* import java.time.LocalDateTime
import java.time.format.* import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeFormatterBuilder
import java.time.format.SignStyle
import java.time.temporal.ChronoField.* import java.time.temporal.ChronoField.*
private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run { private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run {
@ -47,14 +50,14 @@ fun Project.addBenchmarkProperties() {
rootProject.subprojects.forEach { p -> rootProject.subprojects.forEach { p ->
p.extensions.findByType(KScienceReadmeExtension::class.java)?.run { p.extensions.findByType(KScienceReadmeExtension::class.java)?.run {
benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg ->
property("benchmark${cfg.name.replaceFirstChar(Char::uppercase)}") { property("benchmark${cfg.name.capitalize()}") {
val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}") val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}")
val resDirectory = launches.listFiles()?.maxByOrNull { val resDirectory = launches.listFiles()?.maxByOrNull {
LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant() LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant()
} }
if (resDirectory == null) { if (resDirectory == null || !(resDirectory.resolve("jvm.json")).exists()) {
"> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**."
} else { } else {
val reports = val reports =

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("KDocUnresolvedReference") @file:Suppress("KDocUnresolvedReference")

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- <!--
- Copyright 2018-2021 KMath contributors. - Copyright 2018-2021 KMath contributors.
- Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
--> -->
<svg <svg

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- <!--
- Copyright 2018-2021 KMath contributors. - Copyright 2018-2021 KMath contributors.
- Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
--> -->
<svg <svg

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- <!--
- Copyright 2018-2021 KMath contributors. - Copyright 2018-2021 KMath contributors.
- Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
--> -->
<svg <svg

Before

Width:  |  Height:  |  Size: 278 KiB

After

Width:  |  Height:  |  Size: 278 KiB

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- <!--
- Copyright 2018-2021 KMath contributors. - Copyright 2018-2021 KMath contributors.
- Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
--> -->
<svg <svg

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View File

@ -50,35 +50,6 @@ module definitions below. The module stability could have the following levels:
with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool.
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
<!--Current feature list is [here](/docs/features.md)-->
<!--* **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).-->
<!--* **Histograms** Fast multi-dimensional histograms.-->
<!--* **Streaming** Streaming operations on mathematical objects and objects buffers.-->
<!--* **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 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.-->
<!--* **Array statistics** -->
<!--* **Integration** Univariate and multivariate integration framework.-->
<!--* **Probability and distributions**-->
<!--* **Fitting** Non-linear curve fitting facilities-->
## Modules ## Modules
$modules $modules

View File

@ -5,12 +5,7 @@ plugins {
repositories { repositories {
mavenCentral() mavenCentral()
maven("https://repo.kotlin.link") maven("https://repo.kotlin.link")
maven("https://clojars.org/repo")
maven("https://jitpack.io")
maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers") maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers")
maven("http://logicrunch.research.it.uu.se/maven") {
isAllowInsecureProtocol = true
}
} }
dependencies { dependencies {
@ -32,7 +27,7 @@ dependencies {
//jafama //jafama
implementation(project(":kmath-jafama")) implementation(project(":kmath-jafama"))
//multik //multik
implementation(projects.kmathMultik) implementation(project(":kmath-multik"))
implementation("org.nd4j:nd4j-native:1.0.0-beta7") implementation("org.nd4j:nd4j-native:1.0.0-beta7")
@ -57,16 +52,16 @@ dependencies {
kotlin.sourceSets.all { kotlin.sourceSets.all {
with(languageSettings) { with(languageSettings) {
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") optIn("kotlin.contracts.ExperimentalContracts")
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") optIn("kotlin.ExperimentalUnsignedTypes")
useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") optIn("space.kscience.kmath.misc.UnstableKMathAPI")
} }
} }
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> { tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy"
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast

View File

@ -1,22 +1,26 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast
import space.kscience.kmath.expressions.MstField import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.Symbol.Companion.x
import space.kscience.kmath.expressions.interpret
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
fun main() { fun main() {
val expr = MstField { val expr = MstExtendedField {
x * 2.0 + number(2.0) / x - 16.0 x * 2.0 + number(2.0) / x - number(16.0) + asinh(x) / sin(x)
} }.compileToExpression(DoubleField)
val m = DoubleArray(expr.indexer.symbols.size)
val xIdx = expr.indexer.indexOf(x)
repeat(10000000) { repeat(10000000) {
expr.interpret(DoubleField, x to 1.0) m[xIdx] = 1.0
expr(m)
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.fit package space.kscience.kmath.fit

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.functions

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.functions

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.functions

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.functions

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.jafama package space.kscience.kmath.jafama

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.linear package space.kscience.kmath.linear

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.linear package space.kscience.kmath.linear

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.operations package space.kscience.kmath.operations

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.operations package space.kscience.kmath.operations

View File

@ -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.operations package space.kscience.kmath.operations
import space.kscience.kmath.commons.linear.CMLinearSpace import space.kscience.kmath.commons.linear.CMLinearSpace

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.stat package space.kscience.kmath.stat

View File

@ -1,13 +1,13 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.stat package space.kscience.kmath.stat
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import space.kscience.kmath.chains.collectWithState import space.kscience.kmath.chains.combineWithState
import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.distributions.NormalDistribution
private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0) private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
@ -15,11 +15,11 @@ private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0
/** /**
* Averaging. * Averaging.
*/ */
private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChainState(), { it.copy() }) { chain -> private fun Chain<Double>.mean(): Chain<Double> = combineWithState(AveragingChainState(), { it.copy() }) { chain ->
val next = chain.next() val next = chain.next()
num++ num++
value += next value += next
return@collectWithState value / num return@combineWithState value / num
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("unused") @file:Suppress("unused")

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.structures package space.kscience.kmath.structures

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.structures package space.kscience.kmath.structures
@ -36,7 +36,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND<Double, Double
this@StreamDoubleFieldND.shape, this@StreamDoubleFieldND.shape,
shape shape
) )
this is BufferND && this.indexes == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer this is BufferND && this.indices == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer
else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.structures package space.kscience.kmath.structures
@ -19,24 +19,24 @@ fun main() {
measureTimeMillis { measureTimeMillis {
var res = 0.0 var res = 0.0
strides.indices().forEach { res = structure[it] } strides.asSequence().forEach { res = structure[it] }
} // warmup } // warmup
val time1 = measureTimeMillis { val time1 = measureTimeMillis {
var res = 0.0 var res = 0.0
strides.indices().forEach { res = structure[it] } strides.asSequence().forEach { res = structure[it] }
} }
println("Structure reading finished in $time1 millis") println("Structure reading finished in $time1 millis")
val time2 = measureTimeMillis { val time2 = measureTimeMillis {
var res = 0.0 var res = 0.0
strides.indices().forEach { res = buffer[strides.offset(it)] } strides.asSequence().forEach { res = buffer[strides.offset(it)] }
} }
println("Buffer reading finished in $time2 millis") println("Buffer reading finished in $time2 millis")
val time3 = measureTimeMillis { val time3 = measureTimeMillis {
var res = 0.0 var res = 0.0
strides.indices().forEach { res = array[strides.offset(it)] } strides.asSequence().forEach { res = array[strides.offset(it)] }
} }
println("Array reading finished in $time3 millis") println("Array reading finished in $time3 millis")
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.structures package space.kscience.kmath.structures

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.structures package space.kscience.kmath.structures

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.tensors

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.tensors

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.tensors

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.tensors

View File

@ -1,18 +1,18 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.tensors
import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.Multik
import org.jetbrains.kotlinx.multik.api.ndarray import org.jetbrains.kotlinx.multik.api.ndarray
import space.kscience.kmath.multik.multikND import space.kscience.kmath.multik.multikAlgebra
import space.kscience.kmath.nd.one import space.kscience.kmath.nd.one
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
fun main(): Unit = with(DoubleField.multikND) { fun main(): Unit = with(DoubleField.multikAlgebra) {
val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType<Double>().wrap() val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType<Double>().wrap()
val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)).wrap() val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)).wrap()
one(a.shape) - a + b * 3 one(a.shape) - a + b * 3.0
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this 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 package space.kscience.kmath.tensors
@ -9,7 +9,7 @@ import space.kscience.kmath.operations.invoke
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensor
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.toDoubleArray import space.kscience.kmath.tensors.core.copyArray
import kotlin.math.sqrt import kotlin.math.sqrt
const val seed = 100500L const val seed = 100500L
@ -111,7 +111,7 @@ class NeuralNetwork(private val layers: List<Layer>) {
private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra { private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra {
val onesForAnswers = yPred.zeroesLike() val onesForAnswers = yPred.zeroesLike()
yTrue.toDoubleArray().forEachIndexed { index, labelDouble -> yTrue.copyArray().forEachIndexed { index, labelDouble ->
val label = labelDouble.toInt() val label = labelDouble.toInt()
onesForAnswers[intArrayOf(index, label)] = 1.0 onesForAnswers[intArrayOf(index, label)] = 1.0
} }
@ -163,7 +163,7 @@ class NeuralNetwork(private val layers: List<Layer>) {
for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) { for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) {
train(xBatch, yBatch) train(xBatch, yBatch)
} }
println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true))}") println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true).asDouble())}")
} }
} }
@ -230,7 +230,7 @@ fun main() = BroadcastDoubleTensorAlgebra {
val prediction = model.predict(xTest) val prediction = model.predict(xTest)
// process raw prediction via argMax // process raw prediction via argMax
val predictionLabels = prediction.argMax(1, true) val predictionLabels = prediction.argMax(1, true).asDouble()
// find out accuracy // find out accuracy
val acc = accuracy(yTest, predictionLabels) val acc = accuracy(yTest, predictionLabels)

View File

@ -6,11 +6,10 @@
kotlin.code.style=official kotlin.code.style=official
kotlin.mpp.stability.nowarn=true kotlin.mpp.stability.nowarn=true
#kotlin.mpp.enableGranularSourceSetsMetadata=true
#kotlin.native.enableDependencyPropagation=false
kotlin.jupyter.add.scanner=false kotlin.jupyter.add.scanner=false
org.gradle.configureondemand=true org.gradle.configureondemand=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
toolsVersion=0.11.1-kotlin-1.6.10

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

269
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh #!/bin/sh
# #
# Copyright 2015 the original author or authors. # Copyright © 2015-2021 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -17,67 +17,101 @@
# #
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
@ -106,80 +140,95 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD=$( ulimit -H -n ) ||
MAX_FD="$MAX_FD_LIMIT" warn "Could not query maximum file descriptor limit"
fi esac
ulimit -n $MAX_FD case $MAX_FD in #(
if [ $? -ne 0 ] ; then '' | soft) :;; #(
warn "Could not set maximum file descriptor limit: $MAX_FD" *)
fi ulimit -n "$MAX_FD" ||
else warn "Could not set maximum file descriptor limit to $MAX_FD"
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=`save "$@"` # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

View File

@ -1,6 +1,6 @@
# Module kmath-ast # Module kmath-ast
Performance and visualization extensions to MST API. Extensions to MST API: transformations, dynamic compilation and visualization.
- [expression-language](src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser - [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-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
@ -10,7 +10,7 @@ Performance and visualization extensions to MST API.
## Artifact: ## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-14`. The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-17`.
**Gradle:** **Gradle:**
```gradle ```gradle
@ -20,7 +20,7 @@ repositories {
} }
dependencies { dependencies {
implementation 'space.kscience:kmath-ast:0.3.0-dev-14' implementation 'space.kscience:kmath-ast:0.3.0-dev-17'
} }
``` ```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
@ -31,10 +31,30 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:kmath-ast:0.3.0-dev-14") implementation("space.kscience:kmath-ast:0.3.0-dev-17")
} }
``` ```
## Parsing expressions
In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances.
Supported literals:
1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`.
2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`&mdash;all parsed either as `kotlin.Long` or `kotlin.Double`.
Supported binary operators (from the highest precedence to the lowest one):
1. `^`
2. `*`, `/`
3. `+`, `-`
Supported unary operator:
1. `-`, e.&nbsp;g. `-x`
Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples:
1. `sin(x)`
2. `add(x, y)`
## Dynamic expression code generation ## Dynamic expression code generation
### On JVM ### On JVM
@ -42,48 +62,41 @@ dependencies {
`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a `kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a
special implementation of `Expression<T>` with implemented `invoke` function. special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder: For example, the following code:
```kotlin ```kotlin
import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.expressions.* import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.operations.*
import space.kscience.kmath.asm.*
MstField { x + 2 }.compileToExpression(DoubleField) "x+2".parseMath().compileToExpression(ComplexField)
``` ```
... leads to generation of bytecode, which can be decompiled to the following Java class: &mldr; leads to generation of bytecode, which can be decompiled to the following Java class:
```java ```java
package space.kscience.kmath.asm.generated;
import java.util.Map; import java.util.Map;
import kotlin.jvm.functions.Function2; import kotlin.jvm.functions.Function2;
import space.kscience.kmath.asm.internal.MapIntrinsics; import space.kscience.kmath.asm.internal.MapIntrinsics;
import space.kscience.kmath.complex.Complex;
import space.kscience.kmath.expressions.Expression; import space.kscience.kmath.expressions.Expression;
import space.kscience.kmath.expressions.Symbol; import space.kscience.kmath.expressions.Symbol;
public final class AsmCompiledExpression_45045_0 implements Expression<Double> { public final class CompiledExpression_45045_0 implements Expression<Complex> {
private final Object[] constants; private final Object[] constants;
public final Double invoke(Map<Symbol, ? extends Double> arguments) { public Complex invoke(Map<Symbol, ? extends Complex> arguments) {
return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2); Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x");
} return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]);
public AsmCompiledExpression_45045_0(Object[] constants) {
this.constants = constants;
} }
} }
``` ```
#### Known issues Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually.
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class #### Limitations
loading overhead.
- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. - The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead.
- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders.
### On JS ### On JS
@ -129,7 +142,7 @@ An example of emitted Wasm IR in the form of WAT:
) )
``` ```
#### Known issues #### Limitations
- ESTree expression compilation 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/). - WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).

View File

@ -20,7 +20,7 @@ kotlin.js {
kotlin.sourceSets { kotlin.sourceSets {
filter { it.name.contains("test", true) } filter { it.name.contains("test", true) }
.map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings)
.forEach { it.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } .forEach { it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") }
commonMain { commonMain {
dependencies { dependencies {
@ -55,6 +55,11 @@ tasks.dokkaHtml {
dependsOn(tasks.build) dependsOn(tasks.build)
} }
if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1")
tasks.jvmTest {
jvmArgs = (jvmArgs ?: emptyList()) + listOf("-Dspace.kscience.kmath.ast.dump.generated.classes=1")
}
readme { readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))

View File

@ -1,11 +1,31 @@
# Module kmath-ast # Module kmath-ast
Performance and visualization extensions to MST API. Extensions to MST API: transformations, dynamic compilation and visualization.
${features} ${features}
${artifact} ${artifact}
## Parsing expressions
In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances.
Supported literals:
1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`.
2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`&mdash;all parsed either as `kotlin.Long` or `kotlin.Double`.
Supported binary operators (from the highest precedence to the lowest one):
1. `^`
2. `*`, `/`
3. `+`, `-`
Supported unary operator:
1. `-`, e.&nbsp;g. `-x`
Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples:
1. `sin(x)`
2. `add(x, y)`
## Dynamic expression code generation ## Dynamic expression code generation
### On JVM ### On JVM
@ -13,48 +33,66 @@ ${artifact}
`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a `kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a
special implementation of `Expression<T>` with implemented `invoke` function. special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder: For example, the following code:
```kotlin ```kotlin
import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.*
import space.kscience.kmath.asm.*
MstField { x + 2 }.compileToExpression(DoubleField) "x^3-x+3".parseMath().compileToExpression(DoubleField)
``` ```
... leads to generation of bytecode, which can be decompiled to the following Java class: &mldr; leads to generation of bytecode, which can be decompiled to the following Java class:
```java ```java
package space.kscience.kmath.asm.generated; import java.util.*;
import kotlin.jvm.functions.*;
import space.kscience.kmath.asm.internal.*;
import space.kscience.kmath.complex.*;
import space.kscience.kmath.expressions.*;
import java.util.Map; public final class CompiledExpression_45045_0 implements Expression<Complex> {
import kotlin.jvm.functions.Function2;
import space.kscience.kmath.asm.internal.MapIntrinsics;
import space.kscience.kmath.expressions.Expression;
import space.kscience.kmath.expressions.Symbol;
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
private final Object[] constants; private final Object[] constants;
public final Double invoke(Map<Symbol, ? extends Double> arguments) { public Complex invoke(Map<Symbol, ? extends Complex> arguments) {
return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2); Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x");
} return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]);
public AsmCompiledExpression_45045_0(Object[] constants) {
this.constants = constants;
} }
} }
``` ```
#### Known issues For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance:
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class ```java
loading overhead. import java.util.*;
- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. import space.kscience.kmath.asm.internal.*;
import space.kscience.kmath.expressions.*;
public final class CompiledExpression_-386104628_0 implements DoubleExpression {
private final SymbolIndexer indexer;
public SymbolIndexer getIndexer() {
return this.indexer;
}
public double invoke(double[] arguments) {
double var2 = arguments[0];
return Math.pow(var2, 3.0D) - var2 + 3.0D;
}
public final Double invoke(Map<Symbol, ? extends Double> arguments) {
double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue();
return Math.pow(var2, 3.0D) - var2 + 3.0D;
}
}
```
Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually.
#### Limitations
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead.
- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders.
### On JS ### On JS
@ -100,7 +138,7 @@ An example of emitted Wasm IR in the form of WAT:
) )
``` ```
#### Known issues #### Limitations
- ESTree expression compilation 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/). - WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).

View File

@ -0,0 +1,177 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra
/**
* MST form where all values belong to the type [T]. It is optimal for constant folding, dynamic compilation, etc.
*
* @param T the type.
*/
@UnstableKMathAPI
public sealed interface TypedMst<T> {
/**
* A node containing a unary operation.
*
* @param T the type.
* @property operation The identifier of operation.
* @property function The function implementing this operation.
* @property value The argument of this operation.
*/
public class Unary<T>(public val operation: String, public val function: (T) -> T, public val value: TypedMst<T>) :
TypedMst<T> {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Unary<*>
if (operation != other.operation) return false
if (value != other.value) return false
return true
}
override fun hashCode(): Int {
var result = operation.hashCode()
result = 31 * result + value.hashCode()
return result
}
override fun toString(): String = "Unary(operation=$operation, value=$value)"
}
/**
* A node containing binary operation.
*
* @param T the type.
* @property operation The identifier of operation.
* @property function The binary function implementing this operation.
* @property left The left operand.
* @property right The right operand.
*/
public class Binary<T>(
public val operation: String,
public val function: Function<T>,
public val left: TypedMst<T>,
public val right: TypedMst<T>,
) : TypedMst<T> {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Binary<*>
if (operation != other.operation) return false
if (left != other.left) return false
if (right != other.right) return false
return true
}
override fun hashCode(): Int {
var result = operation.hashCode()
result = 31 * result + left.hashCode()
result = 31 * result + right.hashCode()
return result
}
override fun toString(): String = "Binary(operation=$operation, left=$left, right=$right)"
}
/**
* The non-numeric constant value.
*
* @param T the type.
* @property value The held value.
* @property number The number this value corresponds.
*/
public class Constant<T>(public val value: T, public val number: Number?) : TypedMst<T> {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Constant<*>
if (value != other.value) return false
if (number != other.number) return false
return true
}
override fun hashCode(): Int {
var result = value?.hashCode() ?: 0
result = 31 * result + (number?.hashCode() ?: 0)
return result
}
override fun toString(): String = "Constant(value=$value, number=$number)"
}
/**
* The node containing a variable
*
* @param T the type.
* @property symbol The symbol of the variable.
*/
public class Variable<T>(public val symbol: Symbol) : TypedMst<T> {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Variable<*>
if (symbol != other.symbol) return false
return true
}
override fun hashCode(): Int = symbol.hashCode()
override fun toString(): String = "Variable(symbol=$symbol)"
}
}
/**
* Interprets the [TypedMst] node with this [Algebra] and [arguments].
*/
@UnstableKMathAPI
public fun <T> TypedMst<T>.interpret(algebra: Algebra<T>, arguments: Map<Symbol, T>): T = when (this) {
is TypedMst.Unary -> algebra.unaryOperation(operation, interpret(algebra, arguments))
is TypedMst.Binary -> when {
algebra is NumericAlgebra && left is TypedMst.Constant && left.number != null ->
algebra.leftSideNumberOperation(operation, left.number, right.interpret(algebra, arguments))
algebra is NumericAlgebra && right is TypedMst.Constant && right.number != null ->
algebra.rightSideNumberOperation(operation, left.interpret(algebra, arguments), right.number)
else -> algebra.binaryOperation(
operation,
left.interpret(algebra, arguments),
right.interpret(algebra, arguments),
)
}
is TypedMst.Constant -> value
is TypedMst.Variable -> arguments.getValue(symbol)
}
/**
* Interprets the [TypedMst] node with this [Algebra] and optional [arguments].
*/
@UnstableKMathAPI
public fun <T> TypedMst<T>.interpret(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T = interpret(
algebra,
when (arguments.size) {
0 -> emptyMap()
1 -> mapOf(arguments[0])
else -> hashMapOf(*arguments)
},
)
/**
* Interpret this [TypedMst] node as expression.
*/
@UnstableKMathAPI
public fun <T : Any> TypedMst<T>.toExpression(algebra: Algebra<T>): Expression<T> = Expression { arguments ->
interpret(algebra, arguments)
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra
import space.kscience.kmath.operations.bindSymbolOrNull
/**
* Evaluates constants in given [MST] for given [algebra] at the same time with converting to [TypedMst].
*/
@UnstableKMathAPI
public fun <T> MST.evaluateConstants(algebra: Algebra<T>): TypedMst<T> = when (this) {
is MST.Numeric -> TypedMst.Constant(
(algebra as? NumericAlgebra<T>)?.number(value) ?: error("Numeric nodes are not supported by $algebra"),
value,
)
is MST.Unary -> when (val arg = value.evaluateConstants(algebra)) {
is TypedMst.Constant<T> -> {
val value = algebra.unaryOperation(
operation,
arg.value,
)
TypedMst.Constant(value, if (value is Number) value else null)
}
else -> TypedMst.Unary(operation, algebra.unaryOperationFunction(operation), arg)
}
is MST.Binary -> {
val left = left.evaluateConstants(algebra)
val right = right.evaluateConstants(algebra)
when {
left is TypedMst.Constant<T> && right is TypedMst.Constant<T> -> {
val value = when {
algebra is NumericAlgebra && left.number != null -> algebra.leftSideNumberOperation(
operation,
left.number,
right.value,
)
algebra is NumericAlgebra && right.number != null -> algebra.rightSideNumberOperation(
operation,
left.value,
right.number,
)
else -> algebra.binaryOperation(
operation,
left.value,
right.value,
)
}
TypedMst.Constant(value, if (value is Number) value else null)
}
algebra is NumericAlgebra && left is TypedMst.Constant && left.number != null -> TypedMst.Binary(
operation,
algebra.leftSideNumberOperationFunction(operation),
left,
right,
)
algebra is NumericAlgebra && right is TypedMst.Constant && right.number != null -> TypedMst.Binary(
operation,
algebra.rightSideNumberOperationFunction(operation),
left,
right,
)
else -> TypedMst.Binary(operation, algebra.binaryOperationFunction(operation), left, right)
}
}
is Symbol -> {
val boundSymbol = algebra.bindSymbolOrNull(this)
if (boundSymbol != null)
TypedMst.Constant(boundSymbol, if (boundSymbol is Number) boundSymbol else null)
else
TypedMst.Variable(this)
}
}

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast
@ -22,6 +22,7 @@ import space.kscience.kmath.operations.FieldOps
import space.kscience.kmath.operations.GroupOps import space.kscience.kmath.operations.GroupOps
import space.kscience.kmath.operations.PowerOperations import space.kscience.kmath.operations.PowerOperations
import space.kscience.kmath.operations.RingOps import space.kscience.kmath.operations.RingOps
import kotlin.math.floor
/** /**
* better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4. * better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4.
@ -40,9 +41,22 @@ public object ArithmeticsEvaluator : Grammar<MST>() {
private val div: Token by literalToken("/") private val div: Token by literalToken("/")
private val minus: Token by literalToken("-") private val minus: Token by literalToken("-")
private val plus: Token by literalToken("+") private val plus: Token by literalToken("+")
@Suppress("unused")
private val ws: Token by regexToken("\\s+".toRegex(), ignore = true) private val ws: Token by regexToken("\\s+".toRegex(), ignore = true)
private val number: Parser<MST> by num use { MST.Numeric(text.toDouble()) } // TODO Rewrite as custom parser to handle numbers with better precision. Currently, numbers like 1e10 are handled while they could be stored as longs without precision loss.
private val number: Parser<MST> by num use {
val d = text.toDoubleOrNull()
MST.Numeric(
if (d == null || d == floor(d) && !d.isInfinite()) {
text.toLongOrNull() ?: text.toDouble()
} else
d
)
}
private val singular: Parser<MST> by id use { Symbol(text) } private val singular: Parser<MST> by id use { Symbol(text) }
private val unaryFunction: Parser<MST> by (id and -lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) private val unaryFunction: Parser<MST> by (id and -lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar)
@ -91,7 +105,8 @@ public object ArithmeticsEvaluator : Grammar<MST>() {
} }
/** /**
* Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or error. * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or
* error.
* *
* @receiver the string to parse. * @receiver the string to parse.
* @return the [MST] node. * @return the [MST] node.

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast
@ -44,6 +44,30 @@ internal class TestCompilerOperations {
assertEquals(1.0, expr(x to 0.0)) assertEquals(1.0, expr(x to 0.0))
} }
@Test
fun testTangent() = runCompilerTest {
val expr = MstExtendedField { tan(x) }.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 0.0))
}
@Test
fun testArcSine() = runCompilerTest {
val expr = MstExtendedField { asin(x) }.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 0.0))
}
@Test
fun testArcCosine() = runCompilerTest {
val expr = MstExtendedField { acos(x) }.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 1.0))
}
@Test
fun testAreaHyperbolicSine() = runCompilerTest {
val expr = MstExtendedField { asinh(x) }.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 0.0))
}
@Test @Test
fun testSubtract() = runCompilerTest { fun testSubtract() = runCompilerTest {
val expr = MstExtendedField { x - x }.compileToExpression(DoubleField) val expr = MstExtendedField { x - x }.compileToExpression(DoubleField)

View File

@ -1,13 +1,15 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast
import space.kscience.kmath.expressions.MstRing import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.Symbol.Companion.x
import space.kscience.kmath.expressions.Symbol.Companion.y
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.IntRing import space.kscience.kmath.operations.IntRing
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
@ -16,11 +18,23 @@ import kotlin.test.assertFailsWith
internal class TestCompilerVariables { internal class TestCompilerVariables {
@Test @Test
fun testVariable() = runCompilerTest { fun testNoVariables() = runCompilerTest {
val expr = "0".parseMath().compileToExpression(DoubleField)
assertEquals(0.0, expr(), 0.0001)
}
@Test
fun testOneVariable() = runCompilerTest {
val expr = MstRing { x }.compileToExpression(IntRing) val expr = MstRing { x }.compileToExpression(IntRing)
assertEquals(1, expr(x to 1)) assertEquals(1, expr(x to 1))
} }
@Test
fun testTwoVariables() = runCompilerTest {
val expr = "y+x/y+x".parseMath().compileToExpression(DoubleField)
assertEquals(8.0, expr(x to 4.0, y to 2.0))
}
@Test @Test
fun testUndefinedVariableFails() = runCompilerTest { fun testUndefinedVariableFails() = runCompilerTest {
val expr = MstRing { x }.compileToExpression(IntRing) val expr = MstRing { x }.compileToExpression(IntRing)

View File

@ -0,0 +1,52 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast
import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.IntRing
import space.kscience.kmath.operations.pi
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.fail
internal class TestFolding {
@Test
fun foldUnary() = assertEquals(
-1,
("-(1)".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant<Int> ?: fail()).value,
)
@Test
fun foldDeepUnary() = assertEquals(
1,
("-(-(1))".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant<Int> ?: fail()).value,
)
@Test
fun foldBinary() = assertEquals(
2,
("1*2".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant<Int> ?: fail()).value,
)
@Test
fun foldDeepBinary() = assertEquals(
10,
("1*2*5".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant<Int> ?: fail()).value,
)
@Test
fun foldSymbol() = assertEquals(
DoubleField.pi,
("pi".parseMath().evaluateConstants(DoubleField) as? TypedMst.Constant<Double> ?: fail()).value,
)
@Test
fun foldNumeric() = assertEquals(
42.toByte(),
("42".parseMath().evaluateConstants(ByteRing) as? TypedMst.Constant<Byte> ?: fail()).value,
)
}

View File

@ -1,13 +1,13 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast
import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.ComplexField import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.expressions.evaluate import space.kscience.kmath.expressions.interpret
import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import kotlin.test.Test import kotlin.test.Test
@ -17,14 +17,14 @@ internal class TestParser {
@Test @Test
fun evaluateParsedMst() { fun evaluateParsedMst() {
val mst = "2+2*(2+2)".parseMath() val mst = "2+2*(2+2)".parseMath()
val res = ComplexField.evaluate(mst) val res = mst.interpret(ComplexField)
assertEquals(Complex(10.0, 0.0), res) assertEquals(Complex(10.0, 0.0), res)
} }
@Test @Test
fun evaluateMstSymbol() { fun evaluateMstSymbol() {
val mst = "i".parseMath() val mst = "i".parseMath()
val res = ComplexField.evaluate(mst) val res = mst.interpret(ComplexField)
assertEquals(ComplexField.i, res) assertEquals(ComplexField.i, res)
} }
@ -32,7 +32,7 @@ internal class TestParser {
@Test @Test
fun evaluateMstUnary() { fun evaluateMstUnary() {
val mst = "sin(0)".parseMath() val mst = "sin(0)".parseMath()
val res = DoubleField.evaluate(mst) val res = mst.interpret(DoubleField)
assertEquals(0.0, res) assertEquals(0.0, res)
} }
@ -53,7 +53,7 @@ internal class TestParser {
} }
val mst = "magic(a, b)".parseMath() val mst = "magic(a, b)".parseMath()
val res = magicalAlgebra.evaluate(mst) val res = mst.interpret(magicalAlgebra)
assertEquals("a ★ b", res) assertEquals("a ★ b", res)
} }
} }

View File

@ -1,39 +1,39 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast
import space.kscience.kmath.expressions.evaluate import space.kscience.kmath.expressions.interpret
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class TestParserPrecedence { internal class TestParserPrecedence {
@Test @Test
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath())) fun test1(): Unit = assertEquals(6.0, "2*2+2".parseMath().interpret(f))
@Test @Test
fun test2(): Unit = assertEquals(6.0, f.evaluate("2+2*2".parseMath())) fun test2(): Unit = assertEquals(6.0, "2+2*2".parseMath().interpret(f))
@Test @Test
fun test3(): Unit = assertEquals(10.0, f.evaluate("2^3+2".parseMath())) fun test3(): Unit = assertEquals(10.0, "2^3+2".parseMath().interpret(f))
@Test @Test
fun test4(): Unit = assertEquals(10.0, f.evaluate("2+2^3".parseMath())) fun test4(): Unit = assertEquals(10.0, "2+2^3".parseMath().interpret(f))
@Test @Test
fun test5(): Unit = assertEquals(16.0, f.evaluate("2^3*2".parseMath())) fun test5(): Unit = assertEquals(16.0, "2^3*2".parseMath().interpret(f))
@Test @Test
fun test6(): Unit = assertEquals(16.0, f.evaluate("2*2^3".parseMath())) fun test6(): Unit = assertEquals(16.0, "2*2^3".parseMath().interpret(f))
@Test @Test
fun test7(): Unit = assertEquals(18.0, f.evaluate("2+2^3*2".parseMath())) fun test7(): Unit = assertEquals(18.0, "2+2^3*2".parseMath().interpret(f))
@Test @Test
fun test8(): Unit = assertEquals(18.0, f.evaluate("2*2^3+2".parseMath())) fun test8(): Unit = assertEquals(18.0, "2*2^3+2".parseMath().interpret(f))
private companion object { private companion object {
private val f = DoubleField private val f = DoubleField

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast package space.kscience.kmath.ast

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.ast.rendering package space.kscience.kmath.ast.rendering

View File

@ -1,88 +1,52 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.estree package space.kscience.kmath.estree
import space.kscience.kmath.ast.TypedMst
import space.kscience.kmath.ast.evaluateConstants
import space.kscience.kmath.estree.internal.ESTreeBuilder import space.kscience.kmath.estree.internal.ESTreeBuilder
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.MST
import space.kscience.kmath.expressions.MST.*
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.internal.estree.BaseExpression import space.kscience.kmath.internal.estree.BaseExpression
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra
import space.kscience.kmath.operations.bindSymbolOrNull
@PublishedApi
internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
fun ESTreeBuilder<T>.visit(node: MST): BaseExpression = when (node) {
is Symbol -> {
val symbol = algebra.bindSymbolOrNull(node)
if (symbol != null)
constant(symbol)
else
variable(node.identity)
}
is Numeric -> constant(node.value)
is Unary -> when {
algebra is NumericAlgebra && node.value is Numeric -> constant(
algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value))
}
is Binary -> when {
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant(
algebra.binaryOperationFunction(node.operation).invoke(
algebra.number((node.left as Numeric).value),
algebra.number((node.right as Numeric).value)
)
)
algebra is NumericAlgebra && node.left is Numeric -> call(
algebra.leftSideNumberOperationFunction(node.operation),
visit(node.left),
visit(node.right),
)
algebra is NumericAlgebra && node.right is Numeric -> call(
algebra.rightSideNumberOperationFunction(node.operation),
visit(node.left),
visit(node.right),
)
else -> call(
algebra.binaryOperationFunction(node.operation),
visit(node.left),
visit(node.right),
)
}
}
return ESTreeBuilder<T> { visit(this@compileWith) }.instance
}
/** /**
* Create a compiled expression with given [MST] and given [algebra]. * Create a compiled expression with given [MST] and given [algebra].
*/ */
public fun <T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> = compileWith(algebra) @OptIn(UnstableKMathAPI::class)
public fun <T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> {
val typed = evaluateConstants(algebra)
if (typed is TypedMst.Constant<T>) return Expression { typed.value }
fun ESTreeBuilder<T>.visit(node: TypedMst<T>): BaseExpression = when (node) {
is TypedMst.Constant -> constant(node.value)
is TypedMst.Variable -> variable(node.symbol)
is TypedMst.Unary -> call(node.function, visit(node.value))
is TypedMst.Binary -> call(
node.function,
visit(node.left),
visit(node.right),
)
}
return ESTreeBuilder<T> { visit(typed) }.instance
}
/** /**
* Compile given MST to expression and evaluate it against [arguments] * Compile given MST to expression and evaluate it against [arguments]
*/ */
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T = public fun <T : Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
compileToExpression(algebra).invoke(arguments) compileToExpression(algebra)(arguments)
/** /**
* Compile given MST to expression and evaluate it against [arguments] * Compile given MST to expression and evaluate it against [arguments]
*/ */
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T = public fun <T : Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T =
compileToExpression(algebra).invoke(*arguments) compileToExpression(algebra)(*arguments)

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.estree.internal package space.kscience.kmath.estree.internal
@ -61,7 +61,7 @@ internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExp
} }
} }
fun variable(name: String): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name)) fun variable(name: Symbol): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name.identity))
fun call(function: Function<T>, vararg args: BaseExpression): BaseExpression = SimpleCallExpression( fun call(function: Function<T>, vararg args: BaseExpression): BaseExpression = SimpleCallExpression(
optional = false, optional = false,

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.estree.internal.astring package space.kscience.kmath.estree.internal.astring

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:JsModule("astring") @file:JsModule("astring")

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.internal.astring package space.kscience.kmath.internal.astring

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress( @file:Suppress(

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress( @file:Suppress(

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("PackageDirectoryMismatch", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation") @file:Suppress("PackageDirectoryMismatch", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation")

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.internal.emitter package space.kscience.kmath.internal.emitter

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package space.kscience.kmath.internal.estree package space.kscience.kmath.internal.estree

Some files were not shown because too many files have changed in this diff Show More