diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index b0446946a..ccbb99927 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -1,11 +1,18 @@ -@file:Suppress("UNUSED_VARIABLE") - -import space.kscience.kmath.benchmarks.addBenchmarkProperties +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import kotlinx.benchmark.gradle.BenchmarksExtension +import java.time.LocalDateTime +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeFormatterBuilder +import java.time.format.SignStyle +import java.time.temporal.ChronoField.* +import java.util.* plugins { kotlin("multiplatform") alias(spclibs.plugins.kotlin.plugin.allopen) - id("org.jetbrains.kotlinx.benchmark") + alias(spclibs.plugins.kotlinx.benchmark) } allOpen.annotation("org.openjdk.jmh.annotations.State") @@ -158,8 +165,141 @@ kotlin { } } -readme { - maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + +private data class JmhReport( + val jmhVersion: String, + val benchmark: String, + val mode: String, + val threads: Int, + val forks: Int, + val jvm: String, + val jvmArgs: List, + val jdkVersion: String, + val vmName: String, + val vmVersion: String, + val warmupIterations: Int, + val warmupTime: String, + val warmupBatchSize: Int, + val measurementIterations: Int, + val measurementTime: String, + val measurementBatchSize: Int, + val params: Map = emptyMap(), + val primaryMetric: PrimaryMetric, + val secondaryMetrics: Map, +) { + interface Metric { + val score: Double + val scoreError: Double + val scoreConfidence: List + val scorePercentiles: Map + val scoreUnit: String + } + + data class PrimaryMetric( + override val score: Double, + override val scoreError: Double, + override val scoreConfidence: List, + override val scorePercentiles: Map, + override val scoreUnit: String, + val rawDataHistogram: List>>>? = null, + val rawData: List>? = null, + ) : Metric + + data class SecondaryMetric( + override val score: Double, + override val scoreError: Double, + override val scoreConfidence: List, + override val scorePercentiles: Map, + override val scoreUnit: String, + val rawData: List>, + ) : Metric } -addBenchmarkProperties() +readme { + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + + val jsonMapper = jacksonObjectMapper() + + + val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run { + parseCaseInsensitive() + appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + appendLiteral('-') + appendValue(MONTH_OF_YEAR, 2) + appendLiteral('-') + appendValue(DAY_OF_MONTH, 2) + appendLiteral('T') + appendValue(HOUR_OF_DAY, 2) + appendLiteral('.') + appendValue(MINUTE_OF_HOUR, 2) + optionalStart() + appendLiteral('.') + appendValue(SECOND_OF_MINUTE, 2) + optionalStart() + appendFraction(NANO_OF_SECOND, 0, 9, true) + optionalStart() + appendOffsetId() + optionalStart() + appendLiteral('[') + parseCaseSensitive() + appendZoneRegionId() + appendLiteral(']') + toFormatter() + } + + fun noun(number: Number, singular: String, plural: String) = if (number.toLong() == 1L) singular else plural + + extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> + property("benchmark${cfg.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }}") { + val launches = layout.buildDirectory.dir("reports/benchmarks/${cfg.name}").get() + + val resDirectory = launches.files().maxByOrNull { + LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant() + } + + if (resDirectory == null || !(resDirectory.resolve("jvm.json")).exists()) { + "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." + } else { + val reports: List = + jsonMapper.readValue>(resDirectory.resolve("jvm.json")) + + buildString { + appendLine("
") + appendLine("") + appendLine("Report for benchmark configuration ${cfg.name}") + appendLine("") + appendLine() + val first = reports.first() + + appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:") + appendLine() + appendLine("```") + appendLine( + "${first.jvm} ${ + first.jvmArgs.joinToString(" ") + }" + ) + appendLine("```") + + appendLine( + "* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${ + noun(first.warmupIterations, "iteration", "iterations") + } by ${first.warmupTime} and ${first.measurementIterations} measurement ${ + noun(first.measurementIterations, "iteration", "iterations") + } by ${first.measurementTime}." + ) + + appendLine() + appendLine("| Benchmark | Score |") + appendLine("|:---------:|:-----:|") + + reports.forEach { report -> + appendLine("|`${report.benchmark}`|${report.primaryMetric.score} ± ${report.primaryMetric.scoreError} ${report.primaryMetric.scoreUnit}|") + } + + appendLine("
") + } + } + } + } +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 1b4b4b3ab..185df9448 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ import space.kscience.gradle.useApache2Licence import space.kscience.gradle.useSPCTeam plugins { - id("space.kscience.gradle.project") + alias(spclibs.plugins.kscience.project) alias(spclibs.plugins.kotlinx.kover) } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts deleted file mode 100644 index beb2af7f6..000000000 --- a/buildSrc/build.gradle.kts +++ /dev/null @@ -1,33 +0,0 @@ -plugins { - kotlin("jvm") version "1.9.23" - `kotlin-dsl` - `version-catalog` -} - -repositories { - mavenLocal() - maven("https://repo.kotlin.link") - mavenCentral() - gradlePluginPortal() -} - -val toolsVersion = spclibs.versions.tools.get() -val kotlinVersion = spclibs.versions.kotlin.asProvider().get() -val benchmarksVersion = spclibs.versions.kotlinx.benchmark.get() - -dependencies { - api("space.kscience:gradle-tools:$toolsVersion") - //plugins form benchmarks - api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion") - //api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") - //to be used inside build-script only - //implementation(spclibs.kotlinx.serialization.json) - implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.+") -} - -kotlin { - jvmToolchain(11) - compilerOptions { - optIn.add("kotlin.OptIn") - } -} diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts deleted file mode 100644 index 09633711e..000000000 --- a/buildSrc/settings.gradle.kts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") - -plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" -} - -dependencyResolutionManagement { - val projectProperties = java.util.Properties() - file("../gradle.properties").inputStream().use { - projectProperties.load(it) - } - - projectProperties.forEach { key, value -> - extra.set(key.toString(), value) - } - - - val toolsVersion: String = projectProperties["toolsVersion"].toString() - - @Suppress("UnstableApiUsage") - repositories { - mavenLocal() - maven("https://repo.kotlin.link") - mavenCentral() - gradlePluginPortal() - } - - versionCatalogs { - create("spclibs") { - from("space.kscience:version-catalog:$toolsVersion") - } - } -} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt deleted file mode 100644 index 98778e009..000000000 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2024 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -data class JmhReport( - val jmhVersion: String, - val benchmark: String, - val mode: String, - val threads: Int, - val forks: Int, - val jvm: String, - val jvmArgs: List, - val jdkVersion: String, - val vmName: String, - val vmVersion: String, - val warmupIterations: Int, - val warmupTime: String, - val warmupBatchSize: Int, - val measurementIterations: Int, - val measurementTime: String, - val measurementBatchSize: Int, - val params: Map = emptyMap(), - val primaryMetric: PrimaryMetric, - val secondaryMetrics: Map, -) { - interface Metric { - val score: Double - val scoreError: Double - val scoreConfidence: List - val scorePercentiles: Map - val scoreUnit: String - } - - data class PrimaryMetric( - override val score: Double, - override val scoreError: Double, - override val scoreConfidence: List, - override val scorePercentiles: Map, - override val scoreUnit: String, - val rawDataHistogram: List>>>? = null, - val rawData: List>? = null, - ) : Metric - - data class SecondaryMetric( - override val score: Double, - override val scoreError: Double, - override val scoreConfidence: List, - override val scorePercentiles: Map, - override val scoreUnit: String, - val rawData: List>, - ) : Metric -} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt deleted file mode 100644 index ae2083c5f..000000000 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2018-2024 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.benchmarks - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import kotlinx.benchmark.gradle.BenchmarksExtension -import org.gradle.api.Project -import space.kscience.gradle.KScienceReadmeExtension -import java.time.LocalDateTime -import java.time.ZoneId -import java.time.format.DateTimeFormatter -import java.time.format.DateTimeFormatterBuilder -import java.time.format.SignStyle -import java.time.temporal.ChronoField.* -import java.util.* - -private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run { - parseCaseInsensitive() - appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) - appendLiteral('-') - appendValue(MONTH_OF_YEAR, 2) - appendLiteral('-') - appendValue(DAY_OF_MONTH, 2) - appendLiteral('T') - appendValue(HOUR_OF_DAY, 2) - appendLiteral('.') - appendValue(MINUTE_OF_HOUR, 2) - optionalStart() - appendLiteral('.') - appendValue(SECOND_OF_MINUTE, 2) - optionalStart() - appendFraction(NANO_OF_SECOND, 0, 9, true) - optionalStart() - appendOffsetId() - optionalStart() - appendLiteral('[') - parseCaseSensitive() - appendZoneRegionId() - appendLiteral(']') - toFormatter() -} - -private fun noun(number: Number, singular: String, plural: String) = if (number.toLong() == 1L) singular else plural - -private val jsonMapper = jacksonObjectMapper() - -fun Project.addBenchmarkProperties() { - val benchmarksProject = this - rootProject.subprojects.forEach { p -> - p.extensions.findByType(KScienceReadmeExtension::class.java)?.run { - benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> - property("benchmark${cfg.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }}") { - val launches = benchmarksProject.layout.buildDirectory.dir("reports/benchmarks/${cfg.name}").get() - - val resDirectory = launches.files().maxByOrNull { - LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant() - } - - if (resDirectory == null || !(resDirectory.resolve("jvm.json")).exists()) { - "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." - } else { - val reports: List = - jsonMapper.readValue>(resDirectory.resolve("jvm.json")) - - buildString { - appendLine("
") - appendLine("") - appendLine("Report for benchmark configuration ${cfg.name}") - appendLine("") - appendLine() - val first = reports.first() - - appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:") - appendLine() - appendLine("```") - appendLine( - "${first.jvm} ${ - first.jvmArgs.joinToString(" ") - }" - ) - appendLine("```") - - appendLine( - "* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${ - noun(first.warmupIterations, "iteration", "iterations") - } by ${first.warmupTime} and ${first.measurementIterations} measurement ${ - noun(first.measurementIterations, "iteration", "iterations") - } by ${first.measurementTime}." - ) - - appendLine() - appendLine("| Benchmark | Score |") - appendLine("|:---------:|:-----:|") - - reports.forEach { report -> - appendLine("|`${report.benchmark}`|${report.primaryMetric.score} ± ${report.primaryMetric.scoreError} ${report.primaryMetric.scoreUnit}|") - } - - appendLine("
") - } - } - } - } - } - } -} diff --git a/gradle.properties b/gradle.properties index 2b3b0c9ce..724a19ce8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,6 +10,4 @@ org.gradle.jvmargs=-Xmx4096m org.gradle.parallel=true org.gradle.workers.max=4 -toolsVersion=0.15.4-kotlin-2.0.0 -#kotlin.experimental.tryK2=true -#kscience.wasm.disabled=true \ No newline at end of file +toolsVersion=0.15.4-kotlin-2.0.0 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e1add1777..180778767 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,4 +9,6 @@ commons-rng-simple = { module = "org.apache.commons:commons-rng-simple", version commons-rng-sampling = { module = "org.apache.commons:commons-rng-sampling", version.ref = "commons-rng" } multik-core = { module = "org.jetbrains.kotlinx:multik-core", version.ref = "multik" } -multik-default = { module = "org.jetbrains.kotlinx:multik-default", version.ref = "multik" } \ No newline at end of file +multik-default = { module = "org.jetbrains.kotlinx:multik-default", version.ref = "multik" } + +[plugins] \ No newline at end of file diff --git a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt index d7470be56..416ad0838 100644 --- a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt +++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt @@ -109,6 +109,7 @@ public object CMLinearSpace : LinearSpace { override fun Double.times(v: Point): CMVector = v * this + @OptIn(UnstableKMathAPI::class) override fun > computeAttribute(structure: Structure2D, attribute: A): V? { val origin = structure.toCM().origin diff --git a/kmath-ejml/src/jvmMain/kotlin/space/kscience/kmath/ejml/implementations.kt b/kmath-ejml/src/jvmMain/kotlin/space/kscience/kmath/ejml/implementations.kt index 5657f94e3..8588a7cda 100644 --- a/kmath-ejml/src/jvmMain/kotlin/space/kscience/kmath/ejml/implementations.kt +++ b/kmath-ejml/src/jvmMain/kotlin/space/kscience/kmath/ejml/implementations.kt @@ -21,6 +21,7 @@ import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC import space.kscience.attributes.SafeType import space.kscience.attributes.safeTypeOf +import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.complex.Complex import space.kscience.kmath.linear.* import space.kscience.kmath.linear.Matrix @@ -216,6 +217,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace): EjmlDoubleVector = v * this + @OptIn(UnstableKMathAPI::class) override fun > computeAttribute(structure: Structure2D, attribute: A): V? { val origin: DMatrixRMaj = structure.toEjml().origin diff --git a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/samplers/TestMetropolisHastingsSampler.kt b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/samplers/TestMetropolisHastingsSampler.kt index 1261c75e5..72bf2082f 100644 --- a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/samplers/TestMetropolisHastingsSampler.kt +++ b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/samplers/TestMetropolisHastingsSampler.kt @@ -24,7 +24,7 @@ class TestMetropolisHastingsSampler { data class TestSetup(val mean: Double, val startPoint: Double, val sigma: Double = 0.5) - private val sample = 1e6.toInt() + private val sample = 1e5.toInt() private val burnIn = sample / 5 @Test @@ -40,7 +40,7 @@ class TestMetropolisHastingsSampler { .univariateNormal(it.startPoint, it.sigma, distribution::probability) val sampledValues = sampler.sample(generator).discard(burnIn).nextBuffer(sample) - assertEquals(it.mean, Float64Field.mean(sampledValues), 1e-2) + assertEquals(it.mean, Float64Field.mean(sampledValues), 0.05) } } @@ -59,7 +59,7 @@ class TestMetropolisHastingsSampler { } val sampledValues = sampler.sample(generator).discard(burnIn).nextBuffer(sample) - assertEquals(1.0 / setup.mean, Float64Field.mean(sampledValues), 1e-2) + assertEquals(1.0 / setup.mean, Float64Field.mean(sampledValues), 0.1) } } @@ -82,7 +82,7 @@ class TestMetropolisHastingsSampler { } val sampledValues = sampler.sample(generator).discard(burnIn).nextBuffer(sample) - assertEquals(setup.mean * sqrt(PI / 2), Float64Field.mean(sampledValues), 1e-2) + assertEquals(setup.mean * sqrt(PI / 2), Float64Field.mean(sampledValues), 0.05) } } diff --git a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt index 8badbce64..9598109bc 100644 --- a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt +++ b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt @@ -18,7 +18,7 @@ public class RandomSourceGenerator internal constructor( public val source: RandomSource, seed: Long?, ) : RandomGenerator { - internal val random: UniformRandomProvider = seed?.let { RandomSource.create(source, seed) } + internal val random: UniformRandomProvider = seed?.let { source.create(seed) } ?: RandomSource.create(source) override fun nextBoolean(): Boolean = random.nextBoolean() diff --git a/settings.gradle.kts b/settings.gradle.kts index e660bef85..5e610ca85 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,14 +2,31 @@ rootProject.name = "kmath" enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") +pluginManagement { + val toolsVersion: String by extra + + repositories { + mavenLocal() + gradlePluginPortal() + mavenCentral() + maven("https://repo.kotlin.link") + } + + plugins { + id("space.kscience.gradle.project") version toolsVersion + id("space.kscience.gradle.mpp") version toolsVersion + id("space.kscience.gradle.jvm") version toolsVersion + } +} + dependencyResolutionManagement { val toolsVersion: String by extra repositories { mavenLocal() - maven("https://repo.kotlin.link") - mavenCentral() gradlePluginPortal() + mavenCentral() + maven("https://repo.kotlin.link") } versionCatalogs {