diff --git a/.gitignore b/.gitignore index e91684008..d07c3c850 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,4 @@ # Cache of project .gradletasknamecache -artifactory.gradle \ No newline at end of file +gradle.properties \ No newline at end of file diff --git a/README.md b/README.md index 9dd62a21e..75b6e8345 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,48 @@ +Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/scientifik/scientifik.kmath/images/download.svg) ](https://bintray.com/mipt-npm/scientifik/scientifik.kmath/_latestVersion) + # KMath The Kotlin MATHematics library is intended as a Kotlin-based analog to Python's `numpy` library. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. ## Features +Actual feature list is [here](doc/features.md) + * **Algebra** * Algebraic structures like rings, spaces and field (**TODO** add example to wiki) * Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. * Complex numbers backed by the `Field` API (meaning that they will be usable in any structure like vectors and N-dimensional arrays). - * [In progress] advanced linear algebra operations like matrix inversion and LU decomposition. -* **Array-like structures** Full support of [numpy-like ndarrays](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.ndarray.html) including mixed arithmetic operations and function operations over arrays and numbers just like in Python (with the added benefit of static type checking). + * Advanced linear algebra operations like matrix inversion and LU decomposition. -* **Expressions** Expressions are one of the ultimate goals of KMath. By writing a single mathematical expression +* **Array-like structures** Full support of many-dimenstional array-like structures +including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking). + +* **Expressions** By writing a single mathematical expression once, users will be able to apply different types of objects to the expression by providing a context. Exceptions can be used for a wide variety of purposes from high performance calculations to code generation. +* **Histograms** Fast multi-dimensional histograms. + +* **Streaming** Streaming operations on mathematica objects and objects buffers. + +* **Commons-math wrapper** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/) + library in Kotlin code and maybe rewrite some parts to better suit the Kotlin programming paradigm, however there is no fixed roadmap for that. Feel free + to submit a feature request if you want something to be done first. + +* **Koma wrapper** [Koma](https://github.com/kyonifer/koma) is a well established numerics library in kotlin, specifically linear algebra. +The plan is to have wrappers for koma implementations for compatibility with kmath API. + ## Planned features -* **Common mathematics** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/) -library in Kotlin code and maybe rewrite some parts to better suit the Kotlin programming paradigm, however there is no fixed roadmap for that. Feel free -to submit a feature request if you want something to be done first. - * **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 + ## Multi-platform support KMath is developed as a multi-platform library, which means that most of interfaces are declared in the [common module](kmath-core/src/commonMain). @@ -39,6 +60,10 @@ of optimized parts should be better than SciPy. ## Releases +Working builds can be obtained here: [![](https://jitpack.io/v/altavir/kmath.svg)](https://jitpack.io/#altavir/kmath). + +### Development + The project is currently in pre-release stage. Nightly builds can be used by adding an additional repository to the Gradle config like so: ```groovy @@ -52,7 +77,7 @@ or for the Gradle Kotlin DSL: ```kotlin repositories { - maven { setUrl("http://npm.mipt.ru:8081/artifactory/gradle-dev") } + maven("http://npm.mipt.ru:8081/artifactory/gradle-dev") mavenCentral() } ``` @@ -60,17 +85,29 @@ repositories { Then use a regular dependency like so: ```groovy -compile(group: 'scientifik', name: 'kmath-core', version: '0.0.1-SNAPSHOT') +api "scientifik:kmath-core-jvm:0.1.0-dev" ``` or in the Gradle Kotlin DSL: ```kotlin -compile(group = "scientifik", name = "kmath-core", version = "0.0.1-SNAPSHOT") +api("scientifik:kmath-core-jvm:0.1.0-dev") ``` -Working builds can be obtained here: [![](https://jitpack.io/v/altavir/kmath.svg)](https://jitpack.io/#altavir/kmath). +### Release + +Release artifacts are accessible from bintray with following configuration: + +```kotlin +repositories{ + maven("https://dl.bintray.com/mipt-npm/scientifik") +} + +dependencies{ + api("scientifik:kmath-core-jvm:0.1.0") +} +``` ## Contributing -The project requires a lot of additional work. Please fill free to contribute in any way and propose new features. \ No newline at end of file +The project requires a lot of additional work. Please fill free to contribute in any way and propose new features. diff --git a/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt b/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt index e5147b941..2d16cc8f4 100644 --- a/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt +++ b/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt @@ -1,6 +1,5 @@ package scientifik.kmath.structures -import scientifik.kmath.structures.Buffer.Companion.DoubleBufferFactory import kotlin.system.measureTimeMillis @@ -8,7 +7,7 @@ fun main(args: Array) { val n = 6000 - val structure = NDStructure.build(intArrayOf(n, n), DoubleBufferFactory) { 1.0 } + val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 } structure.mapToBuffer { it + 1 } // warm-up diff --git a/build.gradle.kts b/build.gradle.kts index dadb99422..58a5a5bf2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,7 @@ buildscript { val ioVersion: String by rootProject.extra("0.1.5") val coroutinesVersion: String by rootProject.extra("1.1.1") val atomicfuVersion: String by rootProject.extra("0.12.1") + val dokkaVersion: String by rootProject.extra("0.9.17") repositories { //maven("https://dl.bintray.com/kotlin/kotlin-eap") @@ -14,6 +15,8 @@ buildscript { dependencies { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") classpath("org.jfrog.buildinfo:build-info-extractor-gradle:4+") + classpath("com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4") + classpath("org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion") } } @@ -21,20 +24,31 @@ plugins { id("com.jfrog.artifactory") version "4.9.1" apply false } -allprojects { - if (project.name.startsWith("kmath")) { - apply(plugin = "maven-publish") - apply(plugin = "com.jfrog.artifactory") - } +val kmathVersion by extra("0.1.0") +allprojects { group = "scientifik" - version = "0.0.3-dev" + version = kmathVersion repositories { //maven("https://dl.bintray.com/kotlin/kotlin-eap") jcenter() } + apply(plugin = "maven") + apply(plugin = "maven-publish") + + // apply bintray configuration + apply(from = "${rootProject.rootDir}/gradle/bintray.gradle") + + //apply artifactory configuration + apply(from = "${rootProject.rootDir}/gradle/artifactory.gradle") +} + +subprojects { + if (!name.startsWith("kmath")) return@subprojects + + extensions.findByType()?.apply { jvm { compilations.all { @@ -48,9 +62,49 @@ allprojects { languageSettings.progressiveMode = true } } + + + extensions.findByType()?.apply { + publications.filterIsInstance().forEach { publication -> + if (publication.name == "kotlinMultiplatform") { + // for our root metadata publication, set artifactId with a package and project name + publication.artifactId = project.name + } else { + // for targets, set artifactId with a package, project name and target name (e.g. iosX64) + publication.artifactId = "${project.name}-${publication.name}" + } + } + + // Create empty jar for sources classifier to satisfy maven requirements + val stubSources by tasks.registering(Jar::class) { + archiveClassifier.set("sources") + //from(sourceSets.main.get().allSource) + } + + // Create empty jar for javadoc classifier to satisfy maven requirements + val stubJavadoc by tasks.registering(Jar::class) { + archiveClassifier.set("javadoc") + } + + extensions.findByType()?.apply { + + targets.forEach { target -> + val publication = publications.findByName(target.name) as MavenPublication + + // Patch publications with fake javadoc + publication.artifact(stubJavadoc) + + // Remove gradle metadata publishing from all targets which are not native +// if (target.platformType.name != "native") { +// publication.gradleModuleMetadataFile = null +// tasks.matching { it.name == "generateMetadataFileFor${name.capitalize()}Publication" }.all { +// onlyIf { false } +// } +// } + } + } + } } } -if (file("artifactory.gradle").exists()) { - apply(from = "artifactory.gradle") -} + diff --git a/doc/algebra.md b/doc/algebra.md index 2888f9484..437fc3694 100644 --- a/doc/algebra.md +++ b/doc/algebra.md @@ -68,3 +68,44 @@ One important distinction between algebra elements and algebra contexts is that The middle type is needed in case algebra members do not store context. For example, it is not possible to add a context to regular `Double`. The element performs automatic conversions from context types and back. One should used context operations in all important places. The performance of element operations is not guaranteed. + +## Spaces and fields + +An obvious first choice of mathematical objects to implement in a context-oriented style are algebraic elements like spaces, +rings and fields. Those are located in the `scientifik.kmath.operations.Algebra.kt` file. Alongside common contexts, the file includes definitions for algebra elements like `FieldElement`. A `FieldElement` object +stores a reference to the `Field` which contains additive and multiplicative operations, meaning +it has one fixed context attached and does not require explicit external context. So those `MathElements` can be operated without context: + +```kotlin +val c1 = Complex(1.0, 2.0) +val c2 = ComplexField.i +val c3 = c1 + c2 +``` + +`ComplexField` also features special operations to mix complex and real numbers, for example: + +```kotlin +val c1 = Complex(1.0, 2.0) +val c2 = ComplexField.run{ c1 - 1.0} // Returns: [re:0.0, im: 2.0] +val c3 = ComplexField.run{ c1 - i*2.0} +``` + +**Note**: In theory it is possible to add behaviors directly to the context, but currently kotlin syntax does not support +that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and [KEEP-176](https://github.com/Kotlin/KEEP/pull/176) for updates. + +## Nested fields + +Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex elements like so: + +```kotlin +val element = NDElement.complex(shape = intArrayOf(2,2)){ index: IntArray -> + Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble()) +} +``` + +The `element` in this example is a member of the `Field` of 2-d structures, each element of which is a member of its own +`ComplexField`. The important thing is one does not need to create a special n-d class to hold complex +numbers and implement operations on it, one just needs to provide a field for its elements. + +**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts like +`MemorySpec`. diff --git a/doc/buffers.md b/doc/buffers.md index 6208deaff..b0b7489b3 100644 --- a/doc/buffers.md +++ b/doc/buffers.md @@ -1 +1,15 @@ -**TODO** \ No newline at end of file +# Buffers +Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write (with `MutableBuffer`). +There are different types of buffers: + +* Primitive buffers wrapping like `DoubleBuffer` which are wrapping primitive arrays. +* Boxing `ListBuffer` wrapping a list +* Functionally defined `VirtualBuffer` which does not hold a state itself, but provides a function to calculate value +* `MemoryBuffer` allows direct allocation of objects in continuous memory block. + +Some kmath features require a `BufferFactory` class to operate properly. A general convention is to use functions defined in +`Buffer` and `MutableBuffer` companion classes. For example factory `Buffer.Companion::auto` in most cases creates the most suitable +buffer for given reified type (for types with custom memory buffer it still better to use their own `MemoryBuffer.create()` factory). + +## Buffer performance +One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers instead \ No newline at end of file diff --git a/doc/features.md b/doc/features.md index e69de29bb..703dad6bd 100644 --- a/doc/features.md +++ b/doc/features.md @@ -0,0 +1,17 @@ +# Features + +* [Algebra](./algebra.md) - [Context-based](./contexts.md) operations on different primitives and structures. + +* [NDStructures](./nd-structure.md) + +* [Linear algebra](linear) - Matrices, operations and linear equations solving. To be moved to separate module. Currently supports basic +api and multiple library back-ends. + +* [Histograms](./histograms.md) - Multidimensional histogram calculation and operations. + +* [Expressions](./expressions.md) + +* Commons math integration + +* Koma integration + diff --git a/doc/nd-performance.md b/doc/nd-structure.md similarity index 98% rename from doc/nd-performance.md rename to doc/nd-structure.md index 47653e3e8..b61609870 100644 --- a/doc/nd-performance.md +++ b/doc/nd-structure.md @@ -1,3 +1,7 @@ +# Nd-structure generation and operations + +**TODO** + # Performance for n-dimensional structures operations One of the most sought after features of mathematical libraries is the high-performance operations on n-dimensional diff --git a/doc/operations.md b/doc/operations.md deleted file mode 100644 index 425d791e8..000000000 --- a/doc/operations.md +++ /dev/null @@ -1,40 +0,0 @@ -## Spaces and fields - -An obvious first choice of mathematical objects to implement in a context-oriented style are algebraic elements like spaces, -rings and fields. Those are located in the `scientifik.kmath.operations.Algebra.kt` file. Alongside common contexts, the file includes definitions for algebra elements like `FieldElement`. A `FieldElement` object -stores a reference to the `Field` which contains additive and multiplicative operations, meaning -it has one fixed context attached and does not require explicit external context. So those `MathElements` can be operated without context: - -```kotlin -val c1 = Complex(1.0, 2.0) -val c2 = ComplexField.i -val c3 = c1 + c2 -``` - -`ComplexField` also features special operations to mix complex and real numbers, for example: - -```kotlin -val c1 = Complex(1.0, 2.0) -val c2 = ComplexField.run{ c1 - 1.0} // Returns: [re:0.0, im: 2.0] -val c3 = ComplexField.run{ c1 - i*2.0} -``` - -**Note**: In theory it is possible to add behaviors directly to the context, but currently kotlin syntax does not support -that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and [KEEP-176](https://github.com/Kotlin/KEEP/pull/176) for updates. - -## Nested fields - -Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex elements like so: - -```kotlin -val element = NDElement.complex(shape = intArrayOf(2,2)){ index: IntArray -> - Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble()) -} -``` - -The `element` in this example is a member of the `Field` of 2-d structures, each element of which is a member of its own -`ComplexField`. The important thing is one does not need to create a special n-d class to hold complex -numbers and implement operations on it, one just needs to provide a field for its elements. - -**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts like -`BufferSpec`. This feature is in development phase. \ No newline at end of file diff --git a/gradle/artifactory.gradle b/gradle/artifactory.gradle new file mode 100644 index 000000000..12e59642b --- /dev/null +++ b/gradle/artifactory.gradle @@ -0,0 +1,31 @@ +apply plugin: "com.jfrog.artifactory" + +artifactory { + def artifactory_user = project.hasProperty('artifactoryUser') ? project.property('artifactoryUser') : "" + def artifactory_password = project.hasProperty('artifactoryPassword') ? project.property('artifactoryPassword') : "" + def artifactory_contextUrl = 'http://npm.mipt.ru:8081/artifactory' + + contextUrl = artifactory_contextUrl //The base Artifactory URL if not overridden by the publisher/resolver + publish { + repository { + repoKey = 'gradle-dev-local' + username = artifactory_user + password = artifactory_password + } + + defaults { + publications('jvm', 'js', 'kotlinMultiplatform', 'metadata') + publishBuildInfo = false + publishArtifacts = true + publishPom = true + publishIvy = false + } + } + resolve { + repository { + repoKey = 'gradle-dev' + username = artifactory_user + password = artifactory_password + } + } +} \ No newline at end of file diff --git a/gradle/bintray.gradle b/gradle/bintray.gradle new file mode 100644 index 000000000..8da83c860 --- /dev/null +++ b/gradle/bintray.gradle @@ -0,0 +1,85 @@ +apply plugin: 'com.jfrog.bintray' + +def vcs = "https://github.com/mipt-npm/kmath" + +def pomConfig = { + licenses { + license { + name "The Apache Software License, Version 2.0" + url "http://www.apache.org/licenses/LICENSE-2.0.txt" + distribution "repo" + } + } + developers { + developer { + id "MIPT-NPM" + name "MIPT nuclear physics methods laboratory" + organization "MIPT" + organizationUrl "http://npm.mipt.ru" + } + } + scm { + url vcs + } +} + +project.ext.configureMavenCentralMetadata = { pom -> + def root = asNode() + root.appendNode('name', project.name) + root.appendNode('description', project.description) + root.appendNode('url', vcs) + root.children().last() + pomConfig +} + +project.ext.configurePom = pomConfig + + +// Configure publishing +publishing { + repositories { + maven { + url = "https://bintray.com/mipt-npm/scientifik" + } + } + + // Process each publication we have in this project + publications.all { publication -> + // apply changes to pom.xml files, see pom.gradle + pom.withXml(configureMavenCentralMetadata) + + + } +} + +bintray { + user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') + key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') + publish = true + override = true // for multi-platform Kotlin/Native publishing + + pkg { + userOrg = "mipt-npm" + repo = "scientifik" + name = "scientifik.kmath" + issueTrackerUrl = "https://github.com/mipt-npm/kmath/issues" + licenses = ['Apache-2.0'] + vcsUrl = vcs + version { + name = project.version + vcsTag = project.version + released = new Date() + } + } +} + +bintrayUpload.dependsOn publishToMavenLocal + +// This is for easier debugging of bintray uploading problems +bintrayUpload.doFirst { + publications = project.publishing.publications.findAll { + !it.name.contains('-test') && it.name != 'kotlinMultiplatform' + }.collect { + println("Uploading artifact '$it.groupId:$it.artifactId:$it.version' from publication '$it.name'") + it.name//https://github.com/bintray/gradle-bintray-plugin/issues/256 + } +} \ No newline at end of file diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index 305761c01..0ea7b7eff 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -1,5 +1,6 @@ plugins { kotlin("jvm") + `maven-publish` } description = "Commons math binding for kmath" @@ -11,3 +12,18 @@ dependencies { testImplementation("org.jetbrains.kotlin:kotlin-test") testImplementation("org.jetbrains.kotlin:kotlin-test-junit") } + + +val sourcesJar by tasks.registering(Jar::class) { + classifier = "sources" + from(sourceSets.main.get().allSource) +} + +publishing { + publications { + register("jvm", MavenPublication::class) { + from(components["java"]) + artifact(sourcesJar.get()) + } + } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt index 3752f6db5..dbffea8f3 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt @@ -2,6 +2,7 @@ package scientifik.kmath.linear import scientifik.kmath.operations.Ring import scientifik.kmath.structures.* +import kotlin.jvm.JvmSynthetic /** * Basic implementation of Matrix space based on [NDStructure] @@ -32,7 +33,6 @@ class BufferMatrix( } } - override val shape: IntArray get() = intArrayOf(rowNum, colNum) override fun suggestFeature(vararg features: MatrixFeature) = diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt index 92acf2bbb..329933019 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt @@ -4,7 +4,6 @@ import scientifik.kmath.operations.RealField import scientifik.kmath.operations.Ring import scientifik.kmath.operations.sum import scientifik.kmath.structures.* -import scientifik.kmath.structures.Buffer.Companion.DoubleBufferFactory import scientifik.kmath.structures.Buffer.Companion.boxing import kotlin.math.sqrt @@ -33,7 +32,7 @@ interface MatrixContext { /** * Non-boxing double matrix */ - val real = BufferMatrixContext(RealField, DoubleBufferFactory) + val real = BufferMatrixContext(RealField, Buffer.Companion::auto) /** * A structured matrix with custom buffer diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt index a7373f647..d74d0ed4f 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt @@ -42,7 +42,7 @@ interface VectorSpace> : Space> { * Non-boxing double vector space */ fun real(size: Int): BufferVectorSpace { - return realSpaceCache.getOrPut(size) { BufferVectorSpace(size, RealField, Buffer.DoubleBufferFactory) } + return realSpaceCache.getOrPut(size) { BufferVectorSpace(size, RealField, Buffer.Companion::auto) } } /** diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt index 4b4002cbb..3092c9123 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt @@ -1,8 +1,8 @@ package scientifik.kmath.operations import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.MemoryBuffer import scientifik.kmath.structures.MutableBuffer -import scientifik.kmath.structures.ObjectBuffer import scientifik.memory.MemoryReader import scientifik.memory.MemorySpec import scientifik.memory.MemoryWriter @@ -88,10 +88,10 @@ data class Complex(val re: Double, val im: Double) : FieldElement Complex): Buffer { - return ObjectBuffer.create(Complex, size, init) +inline fun Buffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer { + return MemoryBuffer.create(Complex, size, init) } -fun MutableBuffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer { - return ObjectBuffer.create(Complex, size, init) +inline fun MutableBuffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer { + return MemoryBuffer.create(Complex, size, init) } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt index a89729bae..66c4820e5 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt @@ -1,5 +1,8 @@ package scientifik.kmath.structures +import scientifik.kmath.operations.Complex +import scientifik.kmath.operations.complex + typealias BufferFactory = (Int, (Int) -> T) -> Buffer typealias MutableBufferFactory = (Int, (Int) -> T) -> MutableBuffer @@ -43,21 +46,16 @@ interface Buffer { */ @Suppress("UNCHECKED_CAST") inline fun auto(size: Int, crossinline initializer: (Int) -> T): Buffer { + //TODO add resolution based on Annotation or companion resolution return when (T::class) { Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as Buffer Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as Buffer + Complex::class -> complex(size) { initializer(it) as Complex } as Buffer else -> boxing(size, initializer) } } - - val DoubleBufferFactory: BufferFactory = - { size, initializer -> DoubleBuffer(DoubleArray(size, initializer)) } - val ShortBufferFactory: BufferFactory = - { size, initializer -> ShortBuffer(ShortArray(size, initializer)) } - val IntBufferFactory: BufferFactory = { size, initializer -> IntBuffer(IntArray(size, initializer)) } - val LongBufferFactory: BufferFactory = { size, initializer -> LongBuffer(LongArray(size, initializer)) } } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ObjectBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt similarity index 54% rename from kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ObjectBuffer.kt rename to kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt index badf8a483..a09f09165 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ObjectBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt @@ -5,7 +5,7 @@ import scientifik.memory.* /** * A non-boxing buffer based on [ByteBuffer] storage */ -open class ObjectBuffer(protected val memory: Memory, protected val spec: MemorySpec) : Buffer { +open class MemoryBuffer(protected val memory: Memory, protected val spec: MemorySpec) : Buffer { override val size: Int get() = memory.size / spec.objectSize @@ -18,14 +18,14 @@ open class ObjectBuffer(protected val memory: Memory, protected val spe companion object { fun create(spec: MemorySpec, size: Int) = - ObjectBuffer(Memory.allocate(size * spec.objectSize), spec) + MemoryBuffer(Memory.allocate(size * spec.objectSize), spec) inline fun create( spec: MemorySpec, size: Int, crossinline initializer: (Int) -> T - ): ObjectBuffer = - MutableObjectBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> + ): MemoryBuffer = + MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> (0 until size).forEach { buffer[it] = initializer(it) } @@ -33,16 +33,28 @@ open class ObjectBuffer(protected val memory: Memory, protected val spe } } -class MutableObjectBuffer(memory: Memory, spec: MemorySpec) : ObjectBuffer(memory, spec), +class MutableMemoryBuffer(memory: Memory, spec: MemorySpec) : MemoryBuffer(memory, spec), MutableBuffer { private val writer = memory.writer() override fun set(index: Int, value: T) = writer.write(spec, spec.objectSize * index, value) - override fun copy(): MutableBuffer = MutableObjectBuffer(memory.copy(), spec) + override fun copy(): MutableBuffer = MutableMemoryBuffer(memory.copy(), spec) companion object { + fun create(spec: MemorySpec, size: Int) = + MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec) + inline fun create( + spec: MemorySpec, + size: Int, + crossinline initializer: (Int) -> T + ) = + MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> + (0 until size).forEach { + buffer[it] = initializer(it) + } + } } } \ No newline at end of file diff --git a/kmath-memory/src/commonMain/kotlin/scientifik/memory/MemorySpec.kt b/kmath-memory/src/commonMain/kotlin/scientifik/memory/MemorySpec.kt index a3166ecd7..e6da316cf 100644 --- a/kmath-memory/src/commonMain/kotlin/scientifik/memory/MemorySpec.kt +++ b/kmath-memory/src/commonMain/kotlin/scientifik/memory/MemorySpec.kt @@ -1,5 +1,7 @@ package scientifik.memory +import kotlin.reflect.KClass + /** * A specification to read or write custom objects with fixed size in bytes */