From 79042abf5a5b7550871010073d2a567ac510666b Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 18 Jul 2021 05:44:31 +0700 Subject: [PATCH 1/3] Use correct HMPP configuration --- build.gradle.kts | 113 +++++++++++--------- buildSrc/src/main/kotlin/matricesCodegen.kt | 2 +- buildSrc/src/main/kotlin/vectorsCodegen.kt | 2 +- gradle.properties | 3 +- settings.gradle.kts | 3 +- 5 files changed, 66 insertions(+), 57 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f3f3a5a..9c980c2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,8 @@ -@file:Suppress("UNUSED_VARIABLE") - import de.undercouch.gradle.tasks.download.Download import org.jetbrains.dokka.gradle.DokkaTask +import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile import ru.mipt.npm.gradle.Maturity +import org.jetbrains.kotlin.konan.target.HostManager import space.kscience.kmath.gsl.codegen.matricesCodegen import space.kscience.kmath.gsl.codegen.vectorsCodegen import java.net.URL @@ -20,6 +20,7 @@ version = "0.3.0-dev-3" repositories { mavenCentral() maven("https://repo.kotlin.link") + maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev") } kotlin { @@ -27,17 +28,14 @@ kotlin { data class DownloadLinks(val gsl: String?) - val osName = System.getProperty("os.name") - val isWindows = osName.startsWith("Windows") + val nativeTargets = setOf(linuxX64(), mingwX64()) - val (nativeTarget, downloadLinks) = when { - osName == "Linux" -> linuxX64() to DownloadLinks( + val downloadLinks = when(HostManager.hostOs()) { + "linux" -> DownloadLinks( gsl = "https://anaconda.org/conda-forge/gsl/2.7/download/linux-64/gsl-2.7-he838d99_0.tar.bz2", ) - isWindows -> mingwX64() to DownloadLinks( - gsl = null, - ) + "windows" -> DownloadLinks(gsl = null) else -> { logger.warn("Current OS cannot build any of kmath-gsl targets.") @@ -48,47 +46,6 @@ kotlin { val thirdPartyDir = File("${System.getProperty("user.home")}/.konan/third-party/kmath-gsl-${project.property("version")}") - val main by nativeTarget.compilations.getting - - val test by nativeTarget.compilations.getting { - defaultSourceSet.dependsOn(main.defaultSourceSet) - } - - val libgsl by main.cinterops.creating - - sourceSets { - all { - with(languageSettings) { - progressiveMode = true - useExperimentalAnnotation("kotlin.time.ExperimentalTime") - } - } - - commonMain { - dependencies { - api("space.kscience:kmath-complex:0.3.0-dev-12") - } - } - - val nativeMain by creating { - val codegen by tasks.creating { - matricesCodegen(kotlin.srcDirs.first().absolutePath + "/_Matrices.kt") - vectorsCodegen(kotlin.srcDirs.first().absolutePath + "/_Vectors.kt") - } - - kotlin.srcDirs(files().builtBy(codegen)) - dependsOn(commonMain.get()) - } - - val nativeTest by creating { - dependsOn(nativeMain) - dependsOn(commonTest.get()) - } - - main.defaultSourceSet.dependsOn(nativeMain) - test.defaultSourceSet.dependsOn(nativeTest) - } - val downloadGsl by tasks.creating(Download::class) { if (downloadLinks.gsl == null) { enabled = false @@ -96,7 +53,7 @@ kotlin { } src(downloadLinks.gsl) - dest(File(thirdPartyDir, "libgsl.tar.bz2")) + dest(thirdPartyDir.resolve("libgsl.tar.bz2")) overwrite(false) } @@ -112,7 +69,7 @@ kotlin { } val writeDefFile by tasks.creating { - val file = libgsl.defFile + val file = projectDir.resolve("src/nativeInterop/cinterop/libgsl.def") file.parentFile.mkdirs() if (!file.exists()) file.createNewFile() @@ -141,7 +98,43 @@ kotlin { dependsOn(extractGsl) } - tasks[libgsl.interopProcessingTaskName].dependsOn(writeDefFile) + sourceSets { + all { + with(languageSettings) { + progressiveMode = true + useExperimentalAnnotation("kotlin.time.ExperimentalTime") + } + } + + commonMain { + dependencies { + api("space.kscience:kmath-complex:0.3.0-dev-12") + } + } + + val nativeMain by creating { + val codegen by tasks.creating { + matricesCodegen(kotlin.srcDirs.first().resolve("_Matrices.kt")) + vectorsCodegen(kotlin.srcDirs.first().resolve("_Vectors.kt")) + } + + kotlin.srcDirs(files().builtBy(codegen)) + dependsOn(commonMain.get()) + } + + val nativeTest by creating { + dependsOn(commonTest.get()) + } + + configure(nativeTargets) { + val main by compilations.getting + val test by compilations.getting + main.defaultSourceSet.dependsOn(nativeMain) + test.defaultSourceSet.dependsOn(nativeTest) + val libgsl by main.cinterops.creating + tasks[libgsl.interopProcessingTaskName].dependsOn(writeDefFile) + } + } targets.all { compilations.all { @@ -150,6 +143,20 @@ kotlin { } } +tasks { + withType { + onlyIf { + konanTarget == HostManager.host + } + } + + withType> { + onlyIf { + compilation.konanTarget == HostManager.host + } + } +} + readme { description = "Linear Algebra classes implemented with GNU Scientific Library" maturity = Maturity.PROTOTYPE diff --git a/buildSrc/src/main/kotlin/matricesCodegen.kt b/buildSrc/src/main/kotlin/matricesCodegen.kt index 5c65cce..5318485 100644 --- a/buildSrc/src/main/kotlin/matricesCodegen.kt +++ b/buildSrc/src/main/kotlin/matricesCodegen.kt @@ -63,7 +63,7 @@ private fun Appendable.createMatrixClass( /** * Generates matrices source code for kmath-gsl. */ -fun matricesCodegen(outputFile: String): Unit = File(outputFile).run { +fun matricesCodegen(outputFile: File): Unit = outputFile.run { parentFile.mkdirs() writer().use { it.appendLine("package space.kscience.kmath.gsl") diff --git a/buildSrc/src/main/kotlin/vectorsCodegen.kt b/buildSrc/src/main/kotlin/vectorsCodegen.kt index dfebc8f..9f5955f 100644 --- a/buildSrc/src/main/kotlin/vectorsCodegen.kt +++ b/buildSrc/src/main/kotlin/vectorsCodegen.kt @@ -37,7 +37,7 @@ private fun Appendable.createVectorClass( /** * Generates vectors source code for kmath-gsl. */ -fun vectorsCodegen(outputFile: String): Unit = File(outputFile).run { +fun vectorsCodegen(outputFile: File): Unit = outputFile.run { parentFile.mkdirs() writer().use { w -> diff --git a/gradle.properties b/gradle.properties index 3109acd..d0d3b35 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,9 @@ kotlin.code.style=official +kotlin.mpp.enableCInteropCommonization=true kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.mpp.stability.nowarn=true kotlin.native.enableDependencyPropagation=false +kotlin.native.ignoreDisabledTargets=true org.gradle.configureondemand=true org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m org.gradle.parallel=true -systemProp.org.gradle.internal.publish.checksums.insecure=true diff --git a/settings.gradle.kts b/settings.gradle.kts index 628cce5..9cd1bbc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,12 +3,13 @@ pluginManagement { mavenCentral() gradlePluginPortal() maven("https://repo.kotlin.link") + maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev") } plugins { id("ru.mipt.npm.gradle.project") version "0.10.2-fixrelease-1" id("de.undercouch.download") version "4.1.2" - kotlin("multiplatform") version "1.5.21" + kotlin("multiplatform") version "1.5.30-RC-161" } } From 6c8563eb21d308f13c2408f0a512a5295e086805 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Thu, 19 Aug 2021 16:42:35 +0700 Subject: [PATCH 2/3] Update gradle-tools and kotlin-gradle-plugin --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 9cd1bbc..1cb3e54 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,7 +9,7 @@ pluginManagement { plugins { id("ru.mipt.npm.gradle.project") version "0.10.2-fixrelease-1" id("de.undercouch.download") version "4.1.2" - kotlin("multiplatform") version "1.5.30-RC-161" + kotlin("multiplatform") version "1.5.30-RC" } } From 4190eb6eaf86b7c302328f233d24d1f91aeebe56 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 18 Jul 2021 05:44:31 +0700 Subject: [PATCH 3/3] Add wrappers for gsl_rng and gsl_gaussian --- build.gradle.kts | 30 ++- buildSrc/src/main/kotlin/matricesCodegen.kt | 2 +- buildSrc/src/main/kotlin/vectorsCodegen.kt | 2 +- settings.gradle.kts | 1 - .../kotlin/{ => linear}/GslComplex.kt | 2 +- .../kotlin/{ => linear}/GslLinearSpace.kt | 3 +- .../kotlin/{ => linear}/GslMatrix.kt | 3 +- .../kotlin/{ => linear}/GslPermutation.kt | 3 +- .../kotlin/{ => linear}/GslVector.kt | 3 +- .../kotlin/{ => linear}/_Matrices.kt | 2 +- .../kotlin/{ => linear}/_Vectors.kt | 2 +- .../kotlin/stat/GslNormalDistribution.kt | 25 ++ .../kotlin/stat/GslRandomGenerator.kt | 234 ++++++++++++++++++ src/nativeTest/kotlin/ErrorsHandlingTest.kt | 1 + .../kotlin/GslDoubleLinearSpaceTest.kt | 1 + src/nativeTest/kotlin/GslMatrixRealTest.kt | 1 + .../kotlin/GslNormalDistributionTest.kt | 27 ++ 17 files changed, 325 insertions(+), 17 deletions(-) rename src/nativeMain/kotlin/{ => linear}/GslComplex.kt (98%) rename src/nativeMain/kotlin/{ => linear}/GslLinearSpace.kt (99%) rename src/nativeMain/kotlin/{ => linear}/GslMatrix.kt (92%) rename src/nativeMain/kotlin/{ => linear}/GslPermutation.kt (88%) rename src/nativeMain/kotlin/{ => linear}/GslVector.kt (89%) rename src/nativeMain/kotlin/{ => linear}/_Matrices.kt (98%) rename src/nativeMain/kotlin/{ => linear}/_Vectors.kt (97%) create mode 100644 src/nativeMain/kotlin/stat/GslNormalDistribution.kt create mode 100644 src/nativeMain/kotlin/stat/GslRandomGenerator.kt create mode 100644 src/nativeTest/kotlin/GslNormalDistributionTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 9c980c2..f324ce0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,8 @@ import de.undercouch.gradle.tasks.download.Download import org.jetbrains.dokka.gradle.DokkaTask import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile -import ru.mipt.npm.gradle.Maturity import org.jetbrains.kotlin.konan.target.HostManager +import ru.mipt.npm.gradle.Maturity import space.kscience.kmath.gsl.codegen.matricesCodegen import space.kscience.kmath.gsl.codegen.vectorsCodegen import java.net.URL @@ -30,7 +30,7 @@ kotlin { val nativeTargets = setOf(linuxX64(), mingwX64()) - val downloadLinks = when(HostManager.hostOs()) { + val downloadLinks = when (HostManager.hostOs()) { "linux" -> DownloadLinks( gsl = "https://anaconda.org/conda-forge/gsl/2.7/download/linux-64/gsl-2.7-he838d99_0.tar.bz2", ) @@ -76,7 +76,7 @@ kotlin { file.writeText( """ package=org.gnu.gsl - headers=gsl/gsl_blas.h gsl/gsl_linalg.h gsl/gsl_permute_matrix.h gsl/gsl_matrix.h gsl/gsl_vector.h gsl/gsl_errno.h + headers=gsl/gsl_blas.h gsl/gsl_linalg.h gsl/gsl_permute_matrix.h gsl/gsl_matrix.h gsl/gsl_vector.h gsl/gsl_errno.h gsl/gsl_rng.h gsl/gsl_randist.h gsl/gsl_cdf.h stdint.h linkerOpts.linux=-L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -lblas staticLibraries.linux=libgsl.a libgslcblas.a @@ -92,6 +92,10 @@ kotlin { return gsl_matrix_float_scale(a, x); } + inline void gsl_rng_set2(const gsl_rng * r, uint64_t seed) { + gsl_rng_set(r, seed); + } + """.trimIndent() ) @@ -102,20 +106,22 @@ kotlin { all { with(languageSettings) { progressiveMode = true - useExperimentalAnnotation("kotlin.time.ExperimentalTime") + optIn("kotlin.time.ExperimentalTime") + optIn("kotlin.contracts.ExperimentalContracts") } } commonMain { dependencies { - api("space.kscience:kmath-complex:0.3.0-dev-12") + api("space.kscience:kmath-complex:0.3.0-dev-14") + api("space.kscience:kmath-stat:0.3.0-dev-14") } } val nativeMain by creating { val codegen by tasks.creating { - matricesCodegen(kotlin.srcDirs.first().resolve("_Matrices.kt")) - vectorsCodegen(kotlin.srcDirs.first().resolve("_Vectors.kt")) + matricesCodegen(kotlin.srcDirs.first().resolve("linear/_Matrices.kt")) + vectorsCodegen(kotlin.srcDirs.first().resolve("linear/_Vectors.kt")) } kotlin.srcDirs(files().builtBy(codegen)) @@ -206,6 +212,16 @@ afterEvaluate { "https://mipt-npm.github.io/kmath/kmath-complex/", "https://mipt-npm.github.io/kmath/kmath-complex/kmath-complex/package-list", ) + + externalDocumentationLink( + "https://mipt-npm.github.io/kmath/kmath-state/", + "https://mipt-npm.github.io/kmath/kmath-stat/kmath-stat/package-list", + ) + + externalDocumentationLink( + "https://mipt-npm.github.io/kmath/kmath-coroutines/", + "https://mipt-npm.github.io/kmath/kmath-coroutines/kmath-coroutines/package-list", + ) } } } diff --git a/buildSrc/src/main/kotlin/matricesCodegen.kt b/buildSrc/src/main/kotlin/matricesCodegen.kt index 5318485..8c3b90c 100644 --- a/buildSrc/src/main/kotlin/matricesCodegen.kt +++ b/buildSrc/src/main/kotlin/matricesCodegen.kt @@ -66,7 +66,7 @@ private fun Appendable.createMatrixClass( fun matricesCodegen(outputFile: File): Unit = outputFile.run { parentFile.mkdirs() writer().use { - it.appendLine("package space.kscience.kmath.gsl") + it.appendLine("package space.kscience.kmath.gsl.linear") it.appendLine() it.appendLine("import kotlinx.cinterop.*") it.appendLine("import org.gnu.gsl.*") diff --git a/buildSrc/src/main/kotlin/vectorsCodegen.kt b/buildSrc/src/main/kotlin/vectorsCodegen.kt index 9f5955f..fc3927c 100644 --- a/buildSrc/src/main/kotlin/vectorsCodegen.kt +++ b/buildSrc/src/main/kotlin/vectorsCodegen.kt @@ -41,7 +41,7 @@ fun vectorsCodegen(outputFile: File): Unit = outputFile.run { parentFile.mkdirs() writer().use { w -> - w.appendLine("package space.kscience.kmath.gsl") + w.appendLine("package space.kscience.kmath.gsl.linear") w.appendLine() w.appendLine("import kotlinx.cinterop.*") w.appendLine("import org.gnu.gsl.*") diff --git a/settings.gradle.kts b/settings.gradle.kts index 1cb3e54..b821d78 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,7 +3,6 @@ pluginManagement { mavenCentral() gradlePluginPortal() maven("https://repo.kotlin.link") - maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev") } plugins { diff --git a/src/nativeMain/kotlin/GslComplex.kt b/src/nativeMain/kotlin/linear/GslComplex.kt similarity index 98% rename from src/nativeMain/kotlin/GslComplex.kt rename to src/nativeMain/kotlin/linear/GslComplex.kt index 606b454..1651097 100644 --- a/src/nativeMain/kotlin/GslComplex.kt +++ b/src/nativeMain/kotlin/linear/GslComplex.kt @@ -1,4 +1,4 @@ -package space.kscience.kmath.gsl +package space.kscience.kmath.gsl.linear import kotlinx.cinterop.* import org.gnu.gsl.* diff --git a/src/nativeMain/kotlin/GslLinearSpace.kt b/src/nativeMain/kotlin/linear/GslLinearSpace.kt similarity index 99% rename from src/nativeMain/kotlin/GslLinearSpace.kt rename to src/nativeMain/kotlin/linear/GslLinearSpace.kt index e789ee2..6ecaf28 100644 --- a/src/nativeMain/kotlin/GslLinearSpace.kt +++ b/src/nativeMain/kotlin/linear/GslLinearSpace.kt @@ -1,10 +1,11 @@ -package space.kscience.kmath.gsl +package space.kscience.kmath.gsl.linear import kotlinx.cinterop.* import org.gnu.gsl.* import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.ComplexField import space.kscience.kmath.complex.toComplex +import space.kscience.kmath.gsl.ensureHasGslErrorHandler import space.kscience.kmath.linear.* import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI diff --git a/src/nativeMain/kotlin/GslMatrix.kt b/src/nativeMain/kotlin/linear/GslMatrix.kt similarity index 92% rename from src/nativeMain/kotlin/GslMatrix.kt rename to src/nativeMain/kotlin/linear/GslMatrix.kt index 20441c8..9131b75 100644 --- a/src/nativeMain/kotlin/GslMatrix.kt +++ b/src/nativeMain/kotlin/linear/GslMatrix.kt @@ -1,7 +1,8 @@ -package space.kscience.kmath.gsl +package space.kscience.kmath.gsl.linear import kotlinx.cinterop.AutofreeScope import kotlinx.cinterop.CStructVar +import space.kscience.kmath.gsl.GslObject import space.kscience.kmath.linear.Matrix import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.structures.asSequence diff --git a/src/nativeMain/kotlin/GslPermutation.kt b/src/nativeMain/kotlin/linear/GslPermutation.kt similarity index 88% rename from src/nativeMain/kotlin/GslPermutation.kt rename to src/nativeMain/kotlin/linear/GslPermutation.kt index c10cb06..bf4c13e 100644 --- a/src/nativeMain/kotlin/GslPermutation.kt +++ b/src/nativeMain/kotlin/linear/GslPermutation.kt @@ -1,4 +1,4 @@ -package space.kscience.kmath.gsl +package space.kscience.kmath.gsl.linear import kotlinx.cinterop.AutofreeScope import kotlinx.cinterop.CPointer @@ -6,6 +6,7 @@ import kotlinx.cinterop.pointed import org.gnu.gsl.gsl_permutation import org.gnu.gsl.gsl_permutation_free import org.gnu.gsl.gsl_permutation_get +import space.kscience.kmath.gsl.GslObject internal class GslPermutation( override val rawNativeHandle: CPointer, diff --git a/src/nativeMain/kotlin/GslVector.kt b/src/nativeMain/kotlin/linear/GslVector.kt similarity index 89% rename from src/nativeMain/kotlin/GslVector.kt rename to src/nativeMain/kotlin/linear/GslVector.kt index feeba6e..022fa97 100644 --- a/src/nativeMain/kotlin/GslVector.kt +++ b/src/nativeMain/kotlin/linear/GslVector.kt @@ -1,7 +1,8 @@ -package space.kscience.kmath.gsl +package space.kscience.kmath.gsl.linear import kotlinx.cinterop.AutofreeScope import kotlinx.cinterop.CStructVar +import space.kscience.kmath.gsl.GslObject import space.kscience.kmath.linear.Point /** diff --git a/src/nativeMain/kotlin/_Matrices.kt b/src/nativeMain/kotlin/linear/_Matrices.kt similarity index 98% rename from src/nativeMain/kotlin/_Matrices.kt rename to src/nativeMain/kotlin/linear/_Matrices.kt index bc2fc26..f7b107d 100644 --- a/src/nativeMain/kotlin/_Matrices.kt +++ b/src/nativeMain/kotlin/linear/_Matrices.kt @@ -1,4 +1,4 @@ -package space.kscience.kmath.gsl +package space.kscience.kmath.gsl.linear import kotlinx.cinterop.* import org.gnu.gsl.* diff --git a/src/nativeMain/kotlin/_Vectors.kt b/src/nativeMain/kotlin/linear/_Vectors.kt similarity index 97% rename from src/nativeMain/kotlin/_Vectors.kt rename to src/nativeMain/kotlin/linear/_Vectors.kt index 72d64b0..faef942 100644 --- a/src/nativeMain/kotlin/_Vectors.kt +++ b/src/nativeMain/kotlin/linear/_Vectors.kt @@ -1,4 +1,4 @@ -package space.kscience.kmath.gsl +package space.kscience.kmath.gsl.linear import kotlinx.cinterop.* import org.gnu.gsl.* diff --git a/src/nativeMain/kotlin/stat/GslNormalDistribution.kt b/src/nativeMain/kotlin/stat/GslNormalDistribution.kt new file mode 100644 index 0000000..69d4aca --- /dev/null +++ b/src/nativeMain/kotlin/stat/GslNormalDistribution.kt @@ -0,0 +1,25 @@ +package space.kscience.kmath.gsl.stat + +import org.gnu.gsl.gsl_cdf_gaussian_P +import org.gnu.gsl.gsl_ran_gaussian +import org.gnu.gsl.gsl_ran_gaussian_pdf +import space.kscience.kmath.chains.Chain +import space.kscience.kmath.chains.SimpleChain +import space.kscience.kmath.distributions.UnivariateDistribution +import space.kscience.kmath.stat.RandomGenerator + +public class GslNormalDistribution(public val mean: Double, public val standardDeviation: Double) : + UnivariateDistribution { + override fun probability(arg: Double): Double = gsl_ran_gaussian_pdf(arg - mean, standardDeviation) + + @Deprecated("Unsafe function.", level = DeprecationLevel.ERROR) + override fun sample(generator: RandomGenerator): Chain { + require(generator is GslRandomGenerator) { "Only GslRandomGenerator generators are supported" } + return SimpleChain { gsl_ran_gaussian(generator.nativeHandle, standardDeviation) + mean } + } + + @Suppress("DEPRECATION", "DEPRECATION_ERROR") + public fun sample(generator: GslRandomGenerator): Chain = sample(generator as RandomGenerator) + + override fun cumulative(arg: Double): Double = gsl_cdf_gaussian_P(arg - mean, standardDeviation) +} diff --git a/src/nativeMain/kotlin/stat/GslRandomGenerator.kt b/src/nativeMain/kotlin/stat/GslRandomGenerator.kt new file mode 100644 index 0000000..aa9542e --- /dev/null +++ b/src/nativeMain/kotlin/stat/GslRandomGenerator.kt @@ -0,0 +1,234 @@ +package space.kscience.kmath.gsl.stat + +import kotlinx.cinterop.* +import org.gnu.gsl.* +import space.kscience.kmath.gsl.GslObject +import space.kscience.kmath.stat.RandomGenerator + +private const val POW_32 = 1L shl 32 + +/** + * Partially derived from + * [https://commons.apache.org/proper/commons-rng/commons-rng-core/apidocs/org/apache/commons/rng/core/source64/LongProvider.html]. + */ +public class GslRandomGenerator internal constructor( + override val rawNativeHandle: CPointer, + public val type: Type, + scope: AutofreeScope, + owned: Boolean, +) : GslObject(scope, owned), RandomGenerator { + public constructor( + scope: AutofreeScope, + type: Type = Type.default, + seed: ULong? = null, + ) : this(checkNotNull(gsl_rng_alloc(type.value)), type, scope, true) { + if (seed != null) gsl_rng_set2(nativeHandle, seed) + } + + public val name: String? + get() = gsl_rng_name(nativeHandle)?.toKString() + + /** + * Provides a bit source for booleans. + * + * A cached value from a call to [nextLong]. + */ + private var booleanSource: Long = 0L + + /** + * The bit mask of the boolean source to obtain the boolean bit. + * + * The bit mask contains a single bit set. This begins at the least + * significant bit and is gradually shifted upwards until overflow to zero. + * + * When zero a new boolean source should be created and the mask set to the + * least significant bit (i.e., 1). + */ + private var booleanBitMask: Long = 0L + + /** + * Provides a source for ints. + * + * A cached value from a call to [nextLong]. + */ + private var intSource: Long = 0L + + /** + * Flag to indicate an int source has been cached. + */ + private var cachedIntSource: Boolean = false + + override fun close() = gsl_rng_free(nativeHandle) + + override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { + val len = toIndex - fromIndex + var max = array.size - 1 + + if (fromIndex < 0 || fromIndex > max) + throw IndexOutOfBoundsException("$fromIndex is out of interval [${0}, ${max}]") + + max = array.size - fromIndex + + if (len < 0 || len > max) + throw IndexOutOfBoundsException("$len is out of interval [${0}, ${max}]") + + var index: Int = fromIndex // Index of first insertion. + + // Index of first insertion plus multiple of 8 part of length + // (i.e., length with 3 least significant bits unset). + val indexLoopLimit: Int = fromIndex + (len and 0x7ffffff8) + + // Start filling in the byte array, 8 bytes at a time. + while (index < indexLoopLimit) { + val random: Long = nextLong() + array[index++] = random.toByte() + array[index++] = (random ushr 8).toByte() + array[index++] = (random ushr 16).toByte() + array[index++] = (random ushr 24).toByte() + array[index++] = (random ushr 32).toByte() + array[index++] = (random ushr 40).toByte() + array[index++] = (random ushr 48).toByte() + array[index++] = (random ushr 56).toByte() + } + + val indexLimit: Int = toIndex // Index of last insertion + 1. + + // Fill in the remaining bytes. + if (index < indexLimit) { + var random = nextLong() + + while (true) { + array[index++] = random.toByte() + + random = if (index < indexLimit) { + random ushr 8 + } else { + break + } + } + } + } + + override fun fork(): RandomGenerator = GslRandomGenerator(scope, type, nextLong().toULong()) + + override fun nextBoolean(): Boolean { + // Shift up. This will eventually overflow and become zero. + booleanBitMask = booleanBitMask shl 1 + + // The mask will either contain a single bit or none. + if (booleanBitMask == 0L) { + // Set the least significant bit + booleanBitMask = 1 + // Get the next value + booleanSource = nextLong() + } + + // Return if the bit is set + return booleanSource and booleanBitMask != 0L + } + + override fun nextDouble(): Double = gsl_rng_uniform(nativeHandle) + + override fun nextInt(): Int { + // Directly store and use the long value as a source for ints + if (cachedIntSource) { + // Consume the cache value + cachedIntSource = false + // Return the lower 32 bits + return intSource.toInt() + } + + // Fill the cache + cachedIntSource = true + intSource = nextLong() + + // Return the upper 32 bits + return (intSource ushr 32).toInt() + } + + override fun nextInt(until: Int): Int { + require(until > 0) { "Must be strictly positive: $until" } + + // Lemire (2019): Fast Random Integer Generation in an Interval + // https://arxiv.org/abs/1805.10941 + + var m: Long = (nextInt().toLong() and 0xffffffffL) * until + var l = m and 0xffffffffL + + if (l < until) { + // 2^32 % n + val t: Long = POW_32 % until + + while (l < t) { + m = (nextInt().toLong() and 0xffffffffL) * until + l = m and 0xffffffffL + } + } + + return (m ushr 32).toInt() + } + + override fun nextLong(): Long = gsl_rng_get(nativeHandle).toLong() + + override fun nextLong(until: Long): Long { + require(until > 0) { "Must be strictly positive: $until" } + + var bits: Long + var `val`: Long + + do { + bits = nextLong() ushr 1 + `val` = bits % until + } while (bits - `val` + (until - 1) < 0) + + return `val` + } + + public enum class Type(internal val value: CPointer) { + borosh13(gsl_rng_borosh13!!), + coveyou(gsl_rng_coveyou!!), + default(gsl_rng_default!!), + fishman18(gsl_rng_fishman18!!), + fishman20(gsl_rng_fishman20!!), + fishman2x(gsl_rng_fishman2x!!), + knuthran(gsl_rng_knuthran!!), + knuthran2(gsl_rng_knuthran2!!), + lecuyer21(gsl_rng_lecuyer21!!), + minstd(gsl_rng_minstd!!), + mrg(gsl_rng_mrg!!), + mt19937(gsl_rng_mt19937!!), + mt19937_1998(gsl_rng_mt19937_1998!!), + mt19937_1999(gsl_rng_mt19937_1999!!), + ran0(gsl_rng_ran0!!), + ran2(gsl_rng_ran2!!), + rand(gsl_rng_rand!!), + rand48(gsl_rng_rand48!!), + random128_bsd(gsl_rng_random128_bsd!!), + random128_glibc2(gsl_rng_random128_glibc2!!), + random128_libc5(gsl_rng_random128_libc5!!), + random256_bsd(gsl_rng_random256_bsd!!), + random256_glibc2(gsl_rng_random256_glibc2!!), + random256_libc5(gsl_rng_random256_libc5!!), + random32_glibc2(gsl_rng_random32_glibc2!!), + random32_libc5(gsl_rng_random32_libc5!!), + random64_bsd(gsl_rng_random64_bsd!!), + random64_libc5(gsl_rng_random64_libc5!!), + random8_bsd(gsl_rng_random8_bsd!!), + random8_glibc2(gsl_rng_random8_glibc2!!), + random8_libc5(gsl_rng_random8_libc5!!), + random_bsd(gsl_rng_random_bsd!!), + random_libc5(gsl_rng_random_libc5!!), + ranf(gsl_rng_ranf!!), + ranlux389(gsl_rng_ranlux389!!), + ranlxs0(gsl_rng_ranlxs0!!), + ranlxs1(gsl_rng_ranlxs1!!), + ranlxs2(gsl_rng_ranlxs2!!), + ranmar(gsl_rng_ranmar!!), + slatec(gsl_rng_slatec!!), + taus(gsl_rng_taus!!), + taus113(gsl_rng_taus113!!), + uni32(gsl_rng_uni32!!), + vax(gsl_rng_vax!!), + waterman14(gsl_rng_waterman14!!), + } +} diff --git a/src/nativeTest/kotlin/ErrorsHandlingTest.kt b/src/nativeTest/kotlin/ErrorsHandlingTest.kt index beb9735..1dd39f9 100644 --- a/src/nativeTest/kotlin/ErrorsHandlingTest.kt +++ b/src/nativeTest/kotlin/ErrorsHandlingTest.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.gsl +import space.kscience.kmath.gsl.linear.GslDoubleLinearSpace import kotlin.test.Test import kotlin.test.assertFailsWith diff --git a/src/nativeTest/kotlin/GslDoubleLinearSpaceTest.kt b/src/nativeTest/kotlin/GslDoubleLinearSpaceTest.kt index 63e4b2b..d6610df 100644 --- a/src/nativeTest/kotlin/GslDoubleLinearSpaceTest.kt +++ b/src/nativeTest/kotlin/GslDoubleLinearSpaceTest.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.gsl +import space.kscience.kmath.gsl.linear.GslDoubleLinearSpace import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.invoke diff --git a/src/nativeTest/kotlin/GslMatrixRealTest.kt b/src/nativeTest/kotlin/GslMatrixRealTest.kt index ebbdd02..f41dbbf 100644 --- a/src/nativeTest/kotlin/GslMatrixRealTest.kt +++ b/src/nativeTest/kotlin/GslMatrixRealTest.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.gsl +import space.kscience.kmath.gsl.linear.GslDoubleLinearSpace import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.structures.toList import kotlin.test.Test diff --git a/src/nativeTest/kotlin/GslNormalDistributionTest.kt b/src/nativeTest/kotlin/GslNormalDistributionTest.kt new file mode 100644 index 0000000..d3341d9 --- /dev/null +++ b/src/nativeTest/kotlin/GslNormalDistributionTest.kt @@ -0,0 +1,27 @@ +package space.kscience.kmath.gsl + +import space.kscience.kmath.distributions.NormalDistribution +import space.kscience.kmath.gsl.stat.GslNormalDistribution +import space.kscience.kmath.samplers.GaussianSampler +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class GslNormalDistributionTest { + @Test + fun pdf() { + assertEquals( + NormalDistribution(GaussianSampler(2.0, 4.0)).probability(0.234), + GslNormalDistribution(2.0, 4.0).probability(0.234), + 1e-15, + ) + } + + @Test + fun cdf() { + assertEquals( + NormalDistribution(GaussianSampler(2.0, 4.0)).cumulative(0.234), + GslNormalDistribution(2.0, 4.0).cumulative(0.234), + 1e-15, + ) + } +}