Dev #194

Merged
altavir merged 266 commits from dev into master 2021-01-20 17:32:32 +03:00
90 changed files with 905 additions and 1042 deletions
Showing only changes of commit 5e4522bb06 - Show all commits

View File

@ -1,11 +1,8 @@
plugins { plugins { id("ru.mipt.npm.publish") apply false }
id("scientifik.publish") apply false
}
val kmathVersion by extra("0.1.4-dev-8") val kmathVersion: String by extra("0.1.4-dev-8")
val bintrayRepo: String by extra("scientifik")
val bintrayRepo by extra("scientifik") val githubProject: String by extra("kmath")
val githubProject by extra("kmath")
allprojects { allprojects {
repositories { repositories {
@ -18,8 +15,4 @@ allprojects {
version = kmathVersion version = kmathVersion
} }
subprojects { subprojects { if (name.startsWith("kmath")) apply(plugin = "ru.mipt.npm.publish") }
if (name.startsWith("kmath")) {
apply(plugin = "scientifik.publish")
}
}

View File

@ -1,16 +1,13 @@
import org.jetbrains.kotlin.allopen.gradle.AllOpenExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
java java
kotlin("jvm") kotlin("jvm")
kotlin("plugin.allopen") version "1.3.72" kotlin("plugin.allopen") version "1.4.0"
id("kotlinx.benchmark") version "0.2.0-dev-8" id("kotlinx.benchmark") version "0.2.0-dev-20"
} }
configure<AllOpenExtension> { allOpen.annotation("org.openjdk.jmh.annotations.State")
annotation("org.openjdk.jmh.annotations.State")
}
repositories { repositories {
maven("http://dl.bintray.com/kyonifer/maven") maven("http://dl.bintray.com/kyonifer/maven")
@ -19,9 +16,7 @@ repositories {
mavenCentral() mavenCentral()
} }
sourceSets { sourceSets.register("benchmarks")
register("benchmarks")
}
dependencies { dependencies {
implementation(project(":kmath-ast")) implementation(project(":kmath-ast"))
@ -34,26 +29,23 @@ dependencies {
implementation(project(":kmath-dimensions")) implementation(project(":kmath-dimensions"))
implementation("com.kyonifer:koma-core-ejml:0.12") implementation("com.kyonifer:koma-core-ejml:0.12")
implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.2.0-npm-dev-6") implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.2.0-npm-dev-6")
implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-8") implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20")
"benchmarksCompile"(sourceSets.main.get().output + sourceSets.main.get().compileClasspath) //sourceSets.main.output + sourceSets.main.runtimeClasspath "benchmarksCompile"(sourceSets.main.get().output + sourceSets.main.get().compileClasspath) //sourceSets.main.output + sourceSets.main.runtimeClasspath
} }
// Configure benchmark // Configure benchmark
benchmark { benchmark {
// Setup configurations // Setup configurations
targets { targets
// This one matches sourceSet name above // This one matches sourceSet name above
register("benchmarks") .register("benchmarks")
}
configurations { configurations.register("fast") {
register("fast") {
warmups = 5 // number of warmup iterations warmups = 5 // number of warmup iterations
iterations = 3 // number of iterations iterations = 3 // number of iterations
iterationTime = 500 // time in seconds per iteration iterationTime = 500 // time in seconds per iteration
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
} }
}
} }
kotlin.sourceSets.all { kotlin.sourceSets.all {
@ -65,7 +57,7 @@ kotlin.sourceSets.all {
tasks.withType<KotlinCompile> { tasks.withType<KotlinCompile> {
kotlinOptions { kotlinOptions {
jvmTarget = Scientifik.JVM_TARGET.toString() jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn" freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn"
} }
} }

View File

@ -2,7 +2,7 @@ package scientifik.kmath.structures
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
fun main(args: Array<String>) { fun main() {
val n = 6000 val n = 6000
val array = DoubleArray(n * n) { 1.0 } val array = DoubleArray(n * n) { 1.0 }

View File

@ -2,9 +2,7 @@ package scientifik.kmath.structures
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
fun main() {
fun main(args: Array<String>) {
val n = 6000 val n = 6000
val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 } val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }

Binary file not shown.

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-6.5.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

21
gradlew.bat vendored
View File

@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -64,21 +64,6 @@ echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View File

@ -1,8 +1,6 @@
plugins { id("scientifik.mpp") } plugins { id("ru.mipt.npm.mpp") }
kotlin.sourceSets { kotlin.sourceSets {
all { languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") }
commonMain { commonMain {
dependencies { dependencies {
api(project(":kmath-core")) api(project(":kmath-core"))

View File

@ -7,20 +7,20 @@ import scientifik.kmath.operations.RealField
/** /**
* A Mathematical Syntax Tree node for mathematical expressions. * A Mathematical Syntax Tree node for mathematical expressions.
*/ */
sealed class MST { public sealed class MST {
/** /**
* A node containing raw string. * A node containing raw string.
* *
* @property value the value of this node. * @property value the value of this node.
*/ */
data class Symbolic(val value: String) : MST() public data class Symbolic(val value: String) : MST()
/** /**
* A node containing a numeric value or scalar. * A node containing a numeric value or scalar.
* *
* @property value the value of this number. * @property value the value of this number.
*/ */
data class Numeric(val value: Number) : MST() public data class Numeric(val value: Number) : MST()
/** /**
* A node containing an unary operation. * A node containing an unary operation.
@ -28,9 +28,7 @@ sealed class MST {
* @property operation the identifier of operation. * @property operation the identifier of operation.
* @property value the argument of this operation. * @property value the argument of this operation.
*/ */
data class Unary(val operation: String, val value: MST) : MST() { public data class Unary(val operation: String, val value: MST) : MST()
companion object
}
/** /**
* A node containing binary operation. * A node containing binary operation.
@ -39,9 +37,7 @@ sealed class MST {
* @property left the left operand. * @property left the left operand.
* @property right the right operand. * @property right the right operand.
*/ */
data class Binary(val operation: String, val left: MST, val right: MST) : MST() { public data class Binary(val operation: String, val left: MST, val right: MST) : MST()
companion object
}
} }
// TODO add a function with named arguments // TODO add a function with named arguments
@ -53,7 +49,7 @@ sealed class MST {
* @param node the node to evaluate. * @param node the node to evaluate.
* @return the value of expression. * @return the value of expression.
*/ */
fun <T> Algebra<T>.evaluate(node: MST): T = when (node) { public fun <T> Algebra<T>.evaluate(node: MST): T = when (node) {
is MST.Numeric -> (this as? NumericAlgebra<T>)?.number(node.value) is MST.Numeric -> (this as? NumericAlgebra<T>)?.number(node.value)
?: error("Numeric nodes are not supported by $this") ?: error("Numeric nodes are not supported by $this")
is MST.Symbolic -> symbol(node.value) is MST.Symbolic -> symbol(node.value)
@ -84,4 +80,4 @@ fun <T> Algebra<T>.evaluate(node: MST): T = when (node) {
* @param algebra the algebra that provides operations. * @param algebra the algebra that provides operations.
* @return the value of expression. * @return the value of expression.
*/ */
fun <T> MST.interpret(algebra: Algebra<T>): T = algebra.evaluate(this) public fun <T> MST.interpret(algebra: Algebra<T>): T = algebra.evaluate(this)

View File

@ -5,7 +5,7 @@ import scientifik.kmath.operations.*
/** /**
* [Algebra] over [MST] nodes. * [Algebra] over [MST] nodes.
*/ */
object MstAlgebra : NumericAlgebra<MST> { public object MstAlgebra : NumericAlgebra<MST> {
override fun number(value: Number): MST = MST.Numeric(value) override fun number(value: Number): MST = MST.Numeric(value)
override fun symbol(value: String): MST = MST.Symbolic(value) override fun symbol(value: String): MST = MST.Symbolic(value)
@ -20,7 +20,7 @@ object MstAlgebra : NumericAlgebra<MST> {
/** /**
* [Space] over [MST] nodes. * [Space] over [MST] nodes.
*/ */
object MstSpace : Space<MST>, NumericAlgebra<MST> { public object MstSpace : Space<MST>, NumericAlgebra<MST> {
override val zero: MST = number(0.0) override val zero: MST = number(0.0)
override fun number(value: Number): MST = MstAlgebra.number(value) override fun number(value: Number): MST = MstAlgebra.number(value)

View File

@ -2,7 +2,6 @@ package scientifik.kmath.ast
import scientifik.kmath.expressions.* import scientifik.kmath.expressions.*
import scientifik.kmath.operations.* import scientifik.kmath.operations.*
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
@ -13,7 +12,7 @@ import kotlin.contracts.contract
* @property algebra the algebra that provides operations. * @property algebra the algebra that provides operations.
* @property mst the [MST] node. * @property mst the [MST] node.
*/ */
class MstExpression<T>(val algebra: Algebra<T>, val mst: MST) : Expression<T> { public class MstExpression<T>(public val algebra: Algebra<T>, public val mst: MST) : Expression<T> {
private inner class InnerAlgebra(val arguments: Map<String, T>) : NumericAlgebra<T> { private inner class InnerAlgebra(val arguments: Map<String, T>) : NumericAlgebra<T> {
override fun symbol(value: String): T = arguments[value] ?: algebra.symbol(value) override fun symbol(value: String): T = arguments[value] ?: algebra.symbol(value)
override fun unaryOperation(operation: String, arg: T): T = algebra.unaryOperation(operation, arg) override fun unaryOperation(operation: String, arg: T): T = algebra.unaryOperation(operation, arg)
@ -33,7 +32,7 @@ class MstExpression<T>(val algebra: Algebra<T>, val mst: MST) : Expression<T> {
/** /**
* Builds [MstExpression] over [Algebra]. * Builds [MstExpression] over [Algebra].
*/ */
inline fun <reified T : Any, A : Algebra<T>, E : Algebra<MST>> A.mst( public inline fun <reified T : Any, A : Algebra<T>, E : Algebra<MST>> A.mst(
mstAlgebra: E, mstAlgebra: E,
block: E.() -> MST block: E.() -> MST
): MstExpression<T> = MstExpression(this, mstAlgebra.block()) ): MstExpression<T> = MstExpression(this, mstAlgebra.block())
@ -41,7 +40,7 @@ inline fun <reified T : Any, A : Algebra<T>, E : Algebra<MST>> A.mst(
/** /**
* Builds [MstExpression] over [Space]. * Builds [MstExpression] over [Space].
*/ */
inline fun <reified T : Any> Space<T>.mstInSpace(block: MstSpace.() -> MST): MstExpression<T> { public inline fun <reified T : Any> Space<T>.mstInSpace(block: MstSpace.() -> MST): MstExpression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return MstExpression(this, MstSpace.block()) return MstExpression(this, MstSpace.block())
} }
@ -49,7 +48,7 @@ inline fun <reified T : Any> Space<T>.mstInSpace(block: MstSpace.() -> MST): Mst
/** /**
* Builds [MstExpression] over [Ring]. * Builds [MstExpression] over [Ring].
*/ */
inline fun <reified T : Any> Ring<T>.mstInRing(block: MstRing.() -> MST): MstExpression<T> { public inline fun <reified T : Any> Ring<T>.mstInRing(block: MstRing.() -> MST): MstExpression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return MstExpression(this, MstRing.block()) return MstExpression(this, MstRing.block())
} }
@ -57,7 +56,7 @@ inline fun <reified T : Any> Ring<T>.mstInRing(block: MstRing.() -> MST): MstExp
/** /**
* Builds [MstExpression] over [Field]. * Builds [MstExpression] over [Field].
*/ */
inline fun <reified T : Any> Field<T>.mstInField(block: MstField.() -> MST): MstExpression<T> { public inline fun <reified T : Any> Field<T>.mstInField(block: MstField.() -> MST): MstExpression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return MstExpression(this, MstField.block()) return MstExpression(this, MstField.block())
} }
@ -65,7 +64,7 @@ inline fun <reified T : Any> Field<T>.mstInField(block: MstField.() -> MST): Mst
/** /**
* Builds [MstExpression] over [ExtendedField]. * Builds [MstExpression] over [ExtendedField].
*/ */
inline fun <reified T : Any> Field<T>.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression<T> { public inline fun <reified T : Any> Field<T>.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return MstExpression(this, MstExtendedField.block()) return MstExpression(this, MstExtendedField.block())
} }
@ -73,7 +72,7 @@ inline fun <reified T : Any> Field<T>.mstInExtendedField(block: MstExtendedField
/** /**
* Builds [MstExpression] over [FunctionalExpressionSpace]. * Builds [MstExpression] over [FunctionalExpressionSpace].
*/ */
inline fun <reified T : Any, A : Space<T>> FunctionalExpressionSpace<T, A>.mstInSpace(block: MstSpace.() -> MST): MstExpression<T> { public inline fun <reified T : Any, A : Space<T>> FunctionalExpressionSpace<T, A>.mstInSpace(block: MstSpace.() -> MST): MstExpression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return algebra.mstInSpace(block) return algebra.mstInSpace(block)
} }
@ -81,7 +80,7 @@ inline fun <reified T : Any, A : Space<T>> FunctionalExpressionSpace<T, A>.mstIn
/** /**
* Builds [MstExpression] over [FunctionalExpressionRing]. * Builds [MstExpression] over [FunctionalExpressionRing].
*/ */
inline fun <reified T : Any, A : Ring<T>> FunctionalExpressionRing<T, A>.mstInRing(block: MstRing.() -> MST): MstExpression<T> { public inline fun <reified T : Any, A : Ring<T>> FunctionalExpressionRing<T, A>.mstInRing(block: MstRing.() -> MST): MstExpression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return algebra.mstInRing(block) return algebra.mstInRing(block)
} }
@ -89,7 +88,7 @@ inline fun <reified T : Any, A : Ring<T>> FunctionalExpressionRing<T, A>.mstInRi
/** /**
* Builds [MstExpression] over [FunctionalExpressionField]. * Builds [MstExpression] over [FunctionalExpressionField].
*/ */
inline fun <reified T : Any, A : Field<T>> FunctionalExpressionField<T, A>.mstInField(block: MstField.() -> MST): MstExpression<T> { public inline fun <reified T : Any, A : Field<T>> FunctionalExpressionField<T, A>.mstInField(block: MstField.() -> MST): MstExpression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return algebra.mstInField(block) return algebra.mstInField(block)
} }
@ -97,7 +96,9 @@ inline fun <reified T : Any, A : Field<T>> FunctionalExpressionField<T, A>.mstIn
/** /**
* Builds [MstExpression] over [FunctionalExpressionExtendedField]. * Builds [MstExpression] over [FunctionalExpressionExtendedField].
*/ */
inline fun <reified T : Any, A : ExtendedField<T>> FunctionalExpressionExtendedField<T, A>.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression<T> { public inline fun <reified T : Any, A : ExtendedField<T>> FunctionalExpressionExtendedField<T, A>.mstInExtendedField(
block: MstExtendedField.() -> MST
): MstExpression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return algebra.mstInExtendedField(block) return algebra.mstInExtendedField(block)
} }

View File

@ -18,7 +18,7 @@ import scientifik.kmath.operations.SpaceOperations
/** /**
* TODO move to core * TODO move to core
*/ */
object ArithmeticsEvaluator : Grammar<MST>() { public object ArithmeticsEvaluator : Grammar<MST>() {
// TODO replace with "...".toRegex() when better-parse 0.4.1 is released // TODO replace with "...".toRegex() when better-parse 0.4.1 is released
private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?") private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?")
private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*") private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*")
@ -35,23 +35,23 @@ object ArithmeticsEvaluator : Grammar<MST>() {
private val number: Parser<MST> by num use { MST.Numeric(text.toDouble()) } private val number: Parser<MST> by num use { MST.Numeric(text.toDouble()) }
private val singular: Parser<MST> by id use { MST.Symbolic(text) } private val singular: Parser<MST> by id use { MST.Symbolic(text) }
private val unaryFunction: Parser<MST> by (id and skip(lpar) and parser(::subSumChain) and skip(rpar)) private val unaryFunction: Parser<MST> by (id and -lpar and parser(::subSumChain) and -rpar)
.map { (id, term) -> MST.Unary(id.text, term) } .map { (id, term) -> MST.Unary(id.text, term) }
private val binaryFunction: Parser<MST> by id private val binaryFunction: Parser<MST> by id
.and(skip(lpar)) .and(-lpar)
.and(parser(::subSumChain)) .and(parser(::subSumChain))
.and(skip(comma)) .and(-comma)
.and(parser(::subSumChain)) .and(parser(::subSumChain))
.and(skip(rpar)) .and(-rpar)
.map { (id, left, right) -> MST.Binary(id.text, left, right) } .map { (id, left, right) -> MST.Binary(id.text, left, right) }
private val term: Parser<MST> by number private val term: Parser<MST> by number
.or(binaryFunction) .or(binaryFunction)
.or(unaryFunction) .or(unaryFunction)
.or(singular) .or(singular)
.or(skip(minus) and parser(::term) map { MST.Unary(SpaceOperations.MINUS_OPERATION, it) }) .or(-minus and parser(::term) map { MST.Unary(SpaceOperations.MINUS_OPERATION, it) })
.or(skip(lpar) and parser(::subSumChain) and skip(rpar)) .or(-lpar and parser(::subSumChain) and -rpar)
private val powChain: Parser<MST> by leftAssociative(term = term, operator = pow) { a, _, b -> private val powChain: Parser<MST> by leftAssociative(term = term, operator = pow) { a, _, b ->
MST.Binary(PowerOperations.POW_OPERATION, a, b) MST.Binary(PowerOperations.POW_OPERATION, a, b)
@ -86,7 +86,7 @@ object ArithmeticsEvaluator : Grammar<MST>() {
* @receiver the string to parse. * @receiver the string to parse.
* @return the [MST] node. * @return the [MST] node.
*/ */
fun String.tryParseMath(): ParseResult<MST> = ArithmeticsEvaluator.tryParseToEnd(this) public fun String.tryParseMath(): ParseResult<MST> = ArithmeticsEvaluator.tryParseToEnd(this)
/** /**
* Parses the string into [MST]. * Parses the string into [MST].
@ -94,4 +94,4 @@ fun String.tryParseMath(): ParseResult<MST> = ArithmeticsEvaluator.tryParseToEnd
* @receiver the string to parse. * @receiver the string to parse.
* @return the [MST] node. * @return the [MST] node.
*/ */
fun String.parseMath(): MST = ArithmeticsEvaluator.parseToEnd(this) public fun String.parseMath(): MST = ArithmeticsEvaluator.parseToEnd(this)

View File

@ -13,7 +13,7 @@ import kotlin.reflect.KClass
/** /**
* Compile given MST to an Expression using AST compiler * Compile given MST to an Expression using AST compiler
*/ */
fun <T : Any> MST.compileWith(type: KClass<T>, algebra: Algebra<T>): Expression<T> { public fun <T : Any> MST.compileWith(type: KClass<T>, algebra: Algebra<T>): Expression<T> {
fun AsmBuilder<T>.visit(node: MST) { fun AsmBuilder<T>.visit(node: MST) {
when (node) { when (node) {
is MST.Symbolic -> { is MST.Symbolic -> {
@ -56,9 +56,9 @@ fun <T : Any> MST.compileWith(type: KClass<T>, algebra: Algebra<T>): Expression<
/** /**
* Compile an [MST] to ASM using given algebra * Compile an [MST] to ASM using given algebra
*/ */
inline fun <reified T : Any> Algebra<T>.expression(mst: MST): Expression<T> = mst.compileWith(T::class, this) public inline fun <reified T : Any> Algebra<T>.expression(mst: MST): Expression<T> = mst.compileWith(T::class, this)
/** /**
* Optimize performance of an [MstExpression] using ASM codegen * Optimize performance of an [MstExpression] using ASM codegen
*/ */
inline fun <reified T : Any> MstExpression<T>.compile(): Expression<T> = mst.compileWith(T::class, algebra) public inline fun <reified T : Any> MstExpression<T>.compile(): Expression<T> = mst.compileWith(T::class, algebra)

View File

@ -1,4 +1,4 @@
plugins { id("scientifik.jvm") } plugins { id("ru.mipt.npm.jvm") }
description = "Commons math binding for kmath" description = "Commons math binding for kmath"
dependencies { dependencies {
@ -8,5 +8,3 @@ dependencies {
api(project(":kmath-functions")) api(project(":kmath-functions"))
api("org.apache.commons:commons-math3:3.6.1") api("org.apache.commons:commons-math3:3.6.1")
} }
kotlin.sourceSets.all { languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") }

View File

@ -7,14 +7,13 @@ import scientifik.kmath.operations.ExtendedField
import scientifik.kmath.operations.Field import scientifik.kmath.operations.Field
import scientifik.kmath.operations.invoke import scientifik.kmath.operations.invoke
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
/** /**
* A field wrapping commons-math derivative structures * A field wrapping commons-math derivative structures
*/ */
class DerivativeStructureField( public class DerivativeStructureField(
val order: Int, public val order: Int,
val parameters: Map<String, Double> public val parameters: Map<String, Double>
) : ExtendedField<DerivativeStructure> { ) : ExtendedField<DerivativeStructure> {
override val zero: DerivativeStructure by lazy { DerivativeStructure(order, parameters.size) } override val zero: DerivativeStructure by lazy { DerivativeStructure(order, parameters.size) }
override val one: DerivativeStructure by lazy { DerivativeStructure(order, parameters.size, 1.0) } override val one: DerivativeStructure by lazy { DerivativeStructure(order, parameters.size, 1.0) }
@ -23,25 +22,24 @@ class DerivativeStructureField(
DerivativeStructure(parameters.size, order, parameters.keys.indexOf(key), value) DerivativeStructure(parameters.size, order, parameters.keys.indexOf(key), value)
} }
val variable: ReadOnlyProperty<Any?, DerivativeStructure> = object : ReadOnlyProperty<Any?, DerivativeStructure> { public val variable: ReadOnlyProperty<Any?, DerivativeStructure> = ReadOnlyProperty { _, property ->
override fun getValue(thisRef: Any?, property: KProperty<*>): DerivativeStructure =
variables[property.name] ?: error("A variable with name ${property.name} does not exist") variables[property.name] ?: error("A variable with name ${property.name} does not exist")
} }
fun variable(name: String, default: DerivativeStructure? = null): DerivativeStructure = public fun variable(name: String, default: DerivativeStructure? = null): DerivativeStructure =
variables[name] ?: default ?: error("A variable with name $name does not exist") variables[name] ?: default ?: error("A variable with name $name does not exist")
fun Number.const(): DerivativeStructure = DerivativeStructure(order, parameters.size, toDouble()) public fun Number.const(): DerivativeStructure = DerivativeStructure(order, parameters.size, toDouble())
fun DerivativeStructure.deriv(parName: String, order: Int = 1): Double { public fun DerivativeStructure.deriv(parName: String, order: Int = 1): Double {
return deriv(mapOf(parName to order)) return deriv(mapOf(parName to order))
} }
fun DerivativeStructure.deriv(orders: Map<String, Int>): Double { public fun DerivativeStructure.deriv(orders: Map<String, Int>): Double {
return getPartialDerivative(*parameters.keys.map { orders[it] ?: 0 }.toIntArray()) return getPartialDerivative(*parameters.keys.map { orders[it] ?: 0 }.toIntArray())
} }
fun DerivativeStructure.deriv(vararg orders: Pair<String, Int>): Double = deriv(mapOf(*orders)) public fun DerivativeStructure.deriv(vararg orders: Pair<String, Int>): Double = deriv(mapOf(*orders))
override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b)
@ -61,7 +59,6 @@ class DerivativeStructureField(
override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin() override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin()
override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos() override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos()
override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan() override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan()
override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh() override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh()
override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh() override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh()
override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh() override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh()
@ -75,7 +72,7 @@ class DerivativeStructureField(
else -> arg.pow(pow.toDouble()) else -> arg.pow(pow.toDouble())
} }
fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure = arg.pow(pow) public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure = arg.pow(pow)
override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp()
override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log()
@ -88,7 +85,8 @@ class DerivativeStructureField(
/** /**
* A constructs that creates a derivative structure with required order on-demand * A constructs that creates a derivative structure with required order on-demand
*/ */
class DiffExpression(val function: DerivativeStructureField.() -> DerivativeStructure) : Expression<Double> { public class DiffExpression(public val function: DerivativeStructureField.() -> DerivativeStructure) :
Expression<Double> {
override operator fun invoke(arguments: Map<String, Double>): Double = DerivativeStructureField( override operator fun invoke(arguments: Map<String, Double>): Double = DerivativeStructureField(
0, 0,
arguments arguments
@ -98,21 +96,20 @@ class DiffExpression(val function: DerivativeStructureField.() -> DerivativeStru
* Get the derivative expression with given orders * Get the derivative expression with given orders
* TODO make result [DiffExpression] * TODO make result [DiffExpression]
*/ */
fun derivative(orders: Map<String, Int>): Expression<Double> = object : Expression<Double> { public fun derivative(orders: Map<String, Int>): Expression<Double> = Expression { arguments ->
override operator fun invoke(arguments: Map<String, Double>): Double =
(DerivativeStructureField(orders.values.max() ?: 0, arguments)) { function().deriv(orders) } (DerivativeStructureField(orders.values.max() ?: 0, arguments)) { function().deriv(orders) }
} }
//TODO add gradient and maybe other vector operators //TODO add gradient and maybe other vector operators
} }
fun DiffExpression.derivative(vararg orders: Pair<String, Int>): Expression<Double> = derivative(mapOf(*orders)) public fun DiffExpression.derivative(vararg orders: Pair<String, Int>): Expression<Double> = derivative(mapOf(*orders))
fun DiffExpression.derivative(name: String): Expression<Double> = derivative(name to 1) public fun DiffExpression.derivative(name: String): Expression<Double> = derivative(name to 1)
/** /**
* A context for [DiffExpression] (not to be confused with [DerivativeStructure]) * A context for [DiffExpression] (not to be confused with [DerivativeStructure])
*/ */
object DiffExpressionAlgebra : ExpressionAlgebra<Double, DiffExpression>, Field<DiffExpression> { public object DiffExpressionAlgebra : ExpressionAlgebra<Double, DiffExpression>, Field<DiffExpression> {
override fun variable(name: String, default: Double?): DiffExpression = override fun variable(name: String, default: Double?): DiffExpression =
DiffExpression { variable(name, default?.const()) } DiffExpression { variable(name, default?.const()) }

View File

@ -1,6 +1,7 @@
plugins { id("scientifik.mpp") } plugins { id("ru.mipt.npm.mpp") }
kotlin.sourceSets { kotlin.sourceSets.commonMain {
all { languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") } dependencies {
commonMain { dependencies { api(project(":kmath-memory")) } } api(project(":kmath-memory"))
}
} }

View File

@ -7,14 +7,14 @@ import scientifik.kmath.linear.Point
* *
* @param T the type of element of this domain. * @param T the type of element of this domain.
*/ */
interface Domain<T : Any> { public interface Domain<T : Any> {
/** /**
* Checks if the specified point is contained in this domain. * Checks if the specified point is contained in this domain.
*/ */
operator fun contains(point: Point<T>): Boolean public operator fun contains(point: Point<T>): Boolean
/** /**
* Number of hyperspace dimensions. * Number of hyperspace dimensions.
*/ */
val dimension: Int public val dimension: Int
} }

View File

@ -25,7 +25,7 @@ import scientifik.kmath.structures.indices
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
class HyperSquareDomain(private val lower: RealBuffer, private val upper: RealBuffer) : RealDomain { public class HyperSquareDomain(private val lower: RealBuffer, private val upper: RealBuffer) : RealDomain {
override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i -> override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i ->
point[i] in lower[i]..upper[i] point[i] in lower[i]..upper[i]

View File

@ -22,8 +22,8 @@ import scientifik.kmath.linear.Point
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
interface RealDomain : Domain<Double> { public interface RealDomain : Domain<Double> {
fun nearestInDomain(point: Point<Double>): Point<Double> public fun nearestInDomain(point: Point<Double>): Point<Double>
/** /**
* The lower edge for the domain going down from point * The lower edge for the domain going down from point
@ -31,7 +31,7 @@ interface RealDomain : Domain<Double> {
* @param point * @param point
* @return * @return
*/ */
fun getLowerBound(num: Int, point: Point<Double>): Double? public fun getLowerBound(num: Int, point: Point<Double>): Double?
/** /**
* The upper edge of the domain going up from point * The upper edge of the domain going up from point
@ -39,25 +39,25 @@ interface RealDomain : Domain<Double> {
* @param point * @param point
* @return * @return
*/ */
fun getUpperBound(num: Int, point: Point<Double>): Double? public fun getUpperBound(num: Int, point: Point<Double>): Double?
/** /**
* Global lower edge * Global lower edge
* @param num * @param num
* @return * @return
*/ */
fun getLowerBound(num: Int): Double? public fun getLowerBound(num: Int): Double?
/** /**
* Global upper edge * Global upper edge
* @param num * @param num
* @return * @return
*/ */
fun getUpperBound(num: Int): Double? public fun getUpperBound(num: Int): Double?
/** /**
* Hyper volume * Hyper volume
* @return * @return
*/ */
fun volume(): Double public fun volume(): Double
} }

View File

@ -17,7 +17,7 @@ package scientifik.kmath.domains
import scientifik.kmath.linear.Point import scientifik.kmath.linear.Point
class UnconstrainedDomain(override val dimension: Int) : RealDomain { public class UnconstrainedDomain(override val dimension: Int) : RealDomain {
override operator fun contains(point: Point<Double>): Boolean = true override operator fun contains(point: Point<Double>): Boolean = true
override fun getLowerBound(num: Int, point: Point<Double>): Double? = Double.NEGATIVE_INFINITY override fun getLowerBound(num: Int, point: Point<Double>): Double? = Double.NEGATIVE_INFINITY

View File

@ -3,8 +3,8 @@ package scientifik.kmath.domains
import scientifik.kmath.linear.Point import scientifik.kmath.linear.Point
import scientifik.kmath.structures.asBuffer import scientifik.kmath.structures.asBuffer
inline class UnivariateDomain(val range: ClosedFloatingPointRange<Double>) : RealDomain { public inline class UnivariateDomain(public val range: ClosedFloatingPointRange<Double>) : RealDomain {
operator fun contains(d: Double): Boolean = range.contains(d) public operator fun contains(d: Double): Boolean = range.contains(d)
override operator fun contains(point: Point<Double>): Boolean { override operator fun contains(point: Point<Double>): Boolean {
require(point.size == 0) require(point.size == 0)

View File

@ -5,45 +5,37 @@ import scientifik.kmath.operations.Algebra
/** /**
* An elementary function that could be invoked on a map of arguments * An elementary function that could be invoked on a map of arguments
*/ */
interface Expression<T> { public fun interface Expression<T> {
/** /**
* Calls this expression from arguments. * Calls this expression from arguments.
* *
* @param arguments the map of arguments. * @param arguments the map of arguments.
* @return the value. * @return the value.
*/ */
operator fun invoke(arguments: Map<String, T>): T public operator fun invoke(arguments: Map<String, T>): T
companion object public companion object
} }
/**
* Create simple lazily evaluated expression inside given algebra
*/
fun <T> Algebra<T>.expression(block: Algebra<T>.(arguments: Map<String, T>) -> T): Expression<T> =
object : Expression<T> {
override operator fun invoke(arguments: Map<String, T>): T = block(arguments)
}
/** /**
* Calls this expression from arguments. * Calls this expression from arguments.
* *
* @param pairs the pair of arguments' names to values. * @param pairs the pair of arguments' names to values.
* @return the value. * @return the value.
*/ */
operator fun <T> Expression<T>.invoke(vararg pairs: Pair<String, T>): T = invoke(mapOf(*pairs)) public operator fun <T> Expression<T>.invoke(vararg pairs: Pair<String, T>): T = invoke(mapOf(*pairs))
/** /**
* A context for expression construction * A context for expression construction
*/ */
interface ExpressionAlgebra<T, E> : Algebra<E> { public interface ExpressionAlgebra<T, E> : Algebra<E> {
/** /**
* Introduce a variable into expression context * Introduce a variable into expression context
*/ */
fun variable(name: String, default: T? = null): E public fun variable(name: String, default: T? = null): E
/** /**
* A constant expression which does not depend on arguments * A constant expression which does not depend on arguments
*/ */
fun const(value: T): E public fun const(value: T): E
} }

View File

@ -39,7 +39,8 @@ internal class FunctionalConstProductExpression<T>(
* *
* @param algebra The algebra to provide for Expressions built. * @param algebra The algebra to provide for Expressions built.
*/ */
abstract class FunctionalExpressionAlgebra<T, A : Algebra<T>>(val algebra: A) : ExpressionAlgebra<T, Expression<T>> { public abstract class FunctionalExpressionAlgebra<T, A : Algebra<T>>(public val algebra: A) :
ExpressionAlgebra<T, Expression<T>> {
/** /**
* Builds an Expression of constant expression which does not depend on arguments. * Builds an Expression of constant expression which does not depend on arguments.
*/ */
@ -66,7 +67,7 @@ abstract class FunctionalExpressionAlgebra<T, A : Algebra<T>>(val algebra: A) :
/** /**
* A context class for [Expression] construction for [Space] algebras. * A context class for [Expression] construction for [Space] algebras.
*/ */
open class FunctionalExpressionSpace<T, A : Space<T>>(algebra: A) : public open class FunctionalExpressionSpace<T, A : Space<T>>(algebra: A) :
FunctionalExpressionAlgebra<T, A>(algebra), Space<Expression<T>> { FunctionalExpressionAlgebra<T, A>(algebra), Space<Expression<T>> {
override val zero: Expression<T> get() = const(algebra.zero) override val zero: Expression<T> get() = const(algebra.zero)
@ -82,10 +83,10 @@ open class FunctionalExpressionSpace<T, A : Space<T>>(algebra: A) :
override fun multiply(a: Expression<T>, k: Number): Expression<T> = override fun multiply(a: Expression<T>, k: Number): Expression<T> =
FunctionalConstProductExpression(algebra, a, k) FunctionalConstProductExpression(algebra, a, k)
operator fun Expression<T>.plus(arg: T): Expression<T> = this + const(arg) public operator fun Expression<T>.plus(arg: T): Expression<T> = this + const(arg)
operator fun Expression<T>.minus(arg: T): Expression<T> = this - const(arg) public operator fun Expression<T>.minus(arg: T): Expression<T> = this - const(arg)
operator fun T.plus(arg: Expression<T>): Expression<T> = arg + this public operator fun T.plus(arg: Expression<T>): Expression<T> = arg + this
operator fun T.minus(arg: Expression<T>): Expression<T> = arg - this public operator fun T.minus(arg: Expression<T>): Expression<T> = arg - this
override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> = override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> =
super<FunctionalExpressionAlgebra>.unaryOperation(operation, arg) super<FunctionalExpressionAlgebra>.unaryOperation(operation, arg)
@ -94,7 +95,7 @@ open class FunctionalExpressionSpace<T, A : Space<T>>(algebra: A) :
super<FunctionalExpressionAlgebra>.binaryOperation(operation, left, right) super<FunctionalExpressionAlgebra>.binaryOperation(operation, left, right)
} }
open class FunctionalExpressionRing<T, A>(algebra: A) : FunctionalExpressionSpace<T, A>(algebra), public open class FunctionalExpressionRing<T, A>(algebra: A) : FunctionalExpressionSpace<T, A>(algebra),
Ring<Expression<T>> where A : Ring<T>, A : NumericAlgebra<T> { Ring<Expression<T>> where A : Ring<T>, A : NumericAlgebra<T> {
override val one: Expression<T> override val one: Expression<T>
get() = const(algebra.one) get() = const(algebra.one)
@ -105,8 +106,8 @@ open class FunctionalExpressionRing<T, A>(algebra: A) : FunctionalExpressionSpac
override fun multiply(a: Expression<T>, b: Expression<T>): Expression<T> = override fun multiply(a: Expression<T>, b: Expression<T>): Expression<T> =
binaryOperation(RingOperations.TIMES_OPERATION, a, b) binaryOperation(RingOperations.TIMES_OPERATION, a, b)
operator fun Expression<T>.times(arg: T): Expression<T> = this * const(arg) public operator fun Expression<T>.times(arg: T): Expression<T> = this * const(arg)
operator fun T.times(arg: Expression<T>): Expression<T> = arg * this public operator fun T.times(arg: Expression<T>): Expression<T> = arg * this
override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> = override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> =
super<FunctionalExpressionSpace>.unaryOperation(operation, arg) super<FunctionalExpressionSpace>.unaryOperation(operation, arg)
@ -115,7 +116,7 @@ open class FunctionalExpressionRing<T, A>(algebra: A) : FunctionalExpressionSpac
super<FunctionalExpressionSpace>.binaryOperation(operation, left, right) super<FunctionalExpressionSpace>.binaryOperation(operation, left, right)
} }
open class FunctionalExpressionField<T, A>(algebra: A) : public open class FunctionalExpressionField<T, A>(algebra: A) :
FunctionalExpressionRing<T, A>(algebra), FunctionalExpressionRing<T, A>(algebra),
Field<Expression<T>> where A : Field<T>, A : NumericAlgebra<T> { Field<Expression<T>> where A : Field<T>, A : NumericAlgebra<T> {
/** /**
@ -124,8 +125,8 @@ open class FunctionalExpressionField<T, A>(algebra: A) :
override fun divide(a: Expression<T>, b: Expression<T>): Expression<T> = override fun divide(a: Expression<T>, b: Expression<T>): Expression<T> =
binaryOperation(FieldOperations.DIV_OPERATION, a, b) binaryOperation(FieldOperations.DIV_OPERATION, a, b)
operator fun Expression<T>.div(arg: T): Expression<T> = this / const(arg) public operator fun Expression<T>.div(arg: T): Expression<T> = this / const(arg)
operator fun T.div(arg: Expression<T>): Expression<T> = arg / this public operator fun T.div(arg: Expression<T>): Expression<T> = arg / this
override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> = override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> =
super<FunctionalExpressionRing>.unaryOperation(operation, arg) super<FunctionalExpressionRing>.unaryOperation(operation, arg)
@ -134,7 +135,7 @@ open class FunctionalExpressionField<T, A>(algebra: A) :
super<FunctionalExpressionRing>.binaryOperation(operation, left, right) super<FunctionalExpressionRing>.binaryOperation(operation, left, right)
} }
open class FunctionalExpressionExtendedField<T, A>(algebra: A) : public open class FunctionalExpressionExtendedField<T, A>(algebra: A) :
FunctionalExpressionField<T, A>(algebra), FunctionalExpressionField<T, A>(algebra),
ExtendedField<Expression<T>> where A : ExtendedField<T>, A : NumericAlgebra<T> { ExtendedField<Expression<T>> where A : ExtendedField<T>, A : NumericAlgebra<T> {
override fun sin(arg: Expression<T>): Expression<T> = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg) override fun sin(arg: Expression<T>): Expression<T> = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg)
@ -156,14 +157,14 @@ open class FunctionalExpressionExtendedField<T, A>(algebra: A) :
super<FunctionalExpressionField>.binaryOperation(operation, left, right) super<FunctionalExpressionField>.binaryOperation(operation, left, right)
} }
inline fun <T, A : Space<T>> A.expressionInSpace(block: FunctionalExpressionSpace<T, A>.() -> Expression<T>): Expression<T> = public inline fun <T, A : Space<T>> A.expressionInSpace(block: FunctionalExpressionSpace<T, A>.() -> Expression<T>): Expression<T> =
FunctionalExpressionSpace(this).block() FunctionalExpressionSpace(this).block()
inline fun <T, A : Ring<T>> A.expressionInRing(block: FunctionalExpressionRing<T, A>.() -> Expression<T>): Expression<T> = public inline fun <T, A : Ring<T>> A.expressionInRing(block: FunctionalExpressionRing<T, A>.() -> Expression<T>): Expression<T> =
FunctionalExpressionRing(this).block() FunctionalExpressionRing(this).block()
inline fun <T, A : Field<T>> A.expressionInField(block: FunctionalExpressionField<T, A>.() -> Expression<T>): Expression<T> = public inline fun <T, A : Field<T>> A.expressionInField(block: FunctionalExpressionField<T, A>.() -> Expression<T>): Expression<T> =
FunctionalExpressionField(this).block() FunctionalExpressionField(this).block()
inline fun <T, A : ExtendedField<T>> A.expressionInExtendedField(block: FunctionalExpressionExtendedField<T, A>.() -> Expression<T>): Expression<T> = public inline fun <T, A : ExtendedField<T>> A.expressionInExtendedField(block: FunctionalExpressionExtendedField<T, A>.() -> Expression<T>): Expression<T> =
FunctionalExpressionExtendedField(this).block() FunctionalExpressionExtendedField(this).block()

View File

@ -11,7 +11,7 @@ import kotlin.contracts.contract
/** /**
* Creates a functional expression with this [Space]. * Creates a functional expression with this [Space].
*/ */
inline fun <T> Space<T>.spaceExpression(block: FunctionalExpressionSpace<T, Space<T>>.() -> Expression<T>): Expression<T> { public inline fun <T> Space<T>.spaceExpression(block: FunctionalExpressionSpace<T, Space<T>>.() -> Expression<T>): Expression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return FunctionalExpressionSpace(this).block() return FunctionalExpressionSpace(this).block()
} }
@ -19,7 +19,7 @@ inline fun <T> Space<T>.spaceExpression(block: FunctionalExpressionSpace<T, Spac
/** /**
* Creates a functional expression with this [Ring]. * Creates a functional expression with this [Ring].
*/ */
inline fun <T> Ring<T>.ringExpression(block: FunctionalExpressionRing<T, Ring<T>>.() -> Expression<T>): Expression<T> { public inline fun <T> Ring<T>.ringExpression(block: FunctionalExpressionRing<T, Ring<T>>.() -> Expression<T>): Expression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return FunctionalExpressionRing(this).block() return FunctionalExpressionRing(this).block()
} }
@ -27,7 +27,7 @@ inline fun <T> Ring<T>.ringExpression(block: FunctionalExpressionRing<T, Ring<T>
/** /**
* Creates a functional expression with this [Field]. * Creates a functional expression with this [Field].
*/ */
inline fun <T> Field<T>.fieldExpression(block: FunctionalExpressionField<T, Field<T>>.() -> Expression<T>): Expression<T> { public inline fun <T> Field<T>.fieldExpression(block: FunctionalExpressionField<T, Field<T>>.() -> Expression<T>): Expression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return FunctionalExpressionField(this).block() return FunctionalExpressionField(this).block()
} }
@ -35,7 +35,7 @@ inline fun <T> Field<T>.fieldExpression(block: FunctionalExpressionField<T, Fiel
/** /**
* Creates a functional expression with this [ExtendedField]. * Creates a functional expression with this [ExtendedField].
*/ */
inline fun <T> ExtendedField<T>.extendedFieldExpression(block: FunctionalExpressionExtendedField<T, ExtendedField<T>>.() -> Expression<T>): Expression<T> { public inline fun <T> ExtendedField<T>.extendedFieldExpression(block: FunctionalExpressionExtendedField<T, ExtendedField<T>>.() -> Expression<T>): Expression<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return FunctionalExpressionExtendedField(this).block() return FunctionalExpressionExtendedField(this).block()
} }

View File

@ -7,7 +7,7 @@ import scientifik.kmath.structures.*
/** /**
* Basic implementation of Matrix space based on [NDStructure] * Basic implementation of Matrix space based on [NDStructure]
*/ */
class BufferMatrixContext<T : Any, R : Ring<T>>( public class BufferMatrixContext<T : Any, R : Ring<T>>(
override val elementContext: R, override val elementContext: R,
private val bufferFactory: BufferFactory<T> private val bufferFactory: BufferFactory<T>
) : GenericMatrixContext<T, R> { ) : GenericMatrixContext<T, R> {
@ -19,11 +19,11 @@ class BufferMatrixContext<T : Any, R : Ring<T>>(
override fun point(size: Int, initializer: (Int) -> T): Point<T> = bufferFactory(size, initializer) override fun point(size: Int, initializer: (Int) -> T): Point<T> = bufferFactory(size, initializer)
companion object public companion object
} }
@Suppress("OVERRIDE_BY_INLINE") @Suppress("OVERRIDE_BY_INLINE")
object RealMatrixContext : GenericMatrixContext<Double, RealField> { public object RealMatrixContext : GenericMatrixContext<Double, RealField> {
override val elementContext: RealField get() = RealField override val elementContext: RealField get() = RealField
@ -35,10 +35,10 @@ object RealMatrixContext : GenericMatrixContext<Double, RealField> {
override inline fun point(size: Int, initializer: (Int) -> Double): Point<Double> = RealBuffer(size, initializer) override inline fun point(size: Int, initializer: (Int) -> Double): Point<Double> = RealBuffer(size, initializer)
} }
class BufferMatrix<T : Any>( public class BufferMatrix<T : Any>(
override val rowNum: Int, override val rowNum: Int,
override val colNum: Int, override val colNum: Int,
val buffer: Buffer<out T>, public val buffer: Buffer<out T>,
override val features: Set<MatrixFeature> = emptySet() override val features: Set<MatrixFeature> = emptySet()
) : FeaturedMatrix<T> { ) : FeaturedMatrix<T> {
@ -90,7 +90,7 @@ class BufferMatrix<T : Any>(
/** /**
* Optimized dot product for real matrices * Optimized dot product for real matrices
*/ */
infix fun BufferMatrix<Double>.dot(other: BufferMatrix<Double>): BufferMatrix<Double> { public infix fun BufferMatrix<Double>.dot(other: BufferMatrix<Double>): BufferMatrix<Double> {
require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
val array = DoubleArray(this.rowNum * other.colNum) val array = DoubleArray(this.rowNum * other.colNum)

View File

@ -11,11 +11,9 @@ import kotlin.math.sqrt
/** /**
* A 2d structure plus optional matrix-specific features * A 2d structure plus optional matrix-specific features
*/ */
interface FeaturedMatrix<T : Any> : Matrix<T> { public interface FeaturedMatrix<T : Any> : Matrix<T> {
override val shape: IntArray get() = intArrayOf(rowNum, colNum) override val shape: IntArray get() = intArrayOf(rowNum, colNum)
public val features: Set<MatrixFeature>
val features: Set<MatrixFeature>
/** /**
* Suggest new feature for this matrix. The result is the new matrix that may or may not reuse existing data structure. * Suggest new feature for this matrix. The result is the new matrix that may or may not reuse existing data structure.
@ -23,12 +21,12 @@ interface FeaturedMatrix<T : Any> : Matrix<T> {
* The implementation does not guarantee to check that matrix actually have the feature, so one should be careful to * The implementation does not guarantee to check that matrix actually have the feature, so one should be careful to
* add only those features that are valid. * add only those features that are valid.
*/ */
fun suggestFeature(vararg features: MatrixFeature): FeaturedMatrix<T> public fun suggestFeature(vararg features: MatrixFeature): FeaturedMatrix<T>
companion object public companion object
} }
inline fun Structure2D.Companion.real(rows: Int, columns: Int, initializer: (Int, Int) -> Double): Matrix<Double> { public inline fun Structure2D.Companion.real(rows: Int, columns: Int, initializer: (Int, Int) -> Double): Matrix<Double> {
contract { callsInPlace(initializer) } contract { callsInPlace(initializer) }
return MatrixContext.real.produce(rows, columns, initializer) return MatrixContext.real.produce(rows, columns, initializer)
} }
@ -36,31 +34,31 @@ inline fun Structure2D.Companion.real(rows: Int, columns: Int, initializer: (Int
/** /**
* Build a square matrix from given elements. * Build a square matrix from given elements.
*/ */
fun <T : Any> Structure2D.Companion.square(vararg elements: T): FeaturedMatrix<T> { public fun <T : Any> Structure2D.Companion.square(vararg elements: T): FeaturedMatrix<T> {
val size: Int = sqrt(elements.size.toDouble()).toInt() val size: Int = sqrt(elements.size.toDouble()).toInt()
require(size * size == elements.size) { "The number of elements ${elements.size} is not a full square" } require(size * size == elements.size) { "The number of elements ${elements.size} is not a full square" }
val buffer = elements.asBuffer() val buffer = elements.asBuffer()
return BufferMatrix(size, size, buffer) return BufferMatrix(size, size, buffer)
} }
val Matrix<*>.features: Set<MatrixFeature> get() = (this as? FeaturedMatrix)?.features ?: emptySet() public val Matrix<*>.features: Set<MatrixFeature> get() = (this as? FeaturedMatrix)?.features ?: emptySet()
/** /**
* Check if matrix has the given feature class * Check if matrix has the given feature class
*/ */
inline fun <reified T : Any> Matrix<*>.hasFeature(): Boolean = public inline fun <reified T : Any> Matrix<*>.hasFeature(): Boolean =
features.find { it is T } != null features.find { it is T } != null
/** /**
* Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria
*/ */
inline fun <reified T : Any> Matrix<*>.getFeature(): T? = public inline fun <reified T : Any> Matrix<*>.getFeature(): T? =
features.filterIsInstance<T>().firstOrNull() features.filterIsInstance<T>().firstOrNull()
/** /**
* Diagonal matrix of ones. The matrix is virtual no actual matrix is created * Diagonal matrix of ones. The matrix is virtual no actual matrix is created
*/ */
fun <T : Any, R : Ring<T>> GenericMatrixContext<T, R>.one(rows: Int, columns: Int): FeaturedMatrix<T> = public fun <T : Any, R : Ring<T>> GenericMatrixContext<T, R>.one(rows: Int, columns: Int): FeaturedMatrix<T> =
VirtualMatrix(rows, columns, DiagonalFeature) { i, j -> VirtualMatrix(rows, columns, DiagonalFeature) { i, j ->
if (i == j) elementContext.one else elementContext.zero if (i == j) elementContext.one else elementContext.zero
} }
@ -69,20 +67,20 @@ fun <T : Any, R : Ring<T>> GenericMatrixContext<T, R>.one(rows: Int, columns: In
/** /**
* A virtual matrix of zeroes * A virtual matrix of zeroes
*/ */
fun <T : Any, R : Ring<T>> GenericMatrixContext<T, R>.zero(rows: Int, columns: Int): FeaturedMatrix<T> = public fun <T : Any, R : Ring<T>> GenericMatrixContext<T, R>.zero(rows: Int, columns: Int): FeaturedMatrix<T> =
VirtualMatrix(rows, columns) { _, _ -> elementContext.zero } VirtualMatrix(rows, columns) { _, _ -> elementContext.zero }
class TransposedFeature<T : Any>(val original: Matrix<T>) : MatrixFeature public class TransposedFeature<T : Any>(public val original: Matrix<T>) : MatrixFeature
/** /**
* Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A`
*/ */
fun <T : Any> Matrix<T>.transpose(): Matrix<T> { public fun <T : Any> Matrix<T>.transpose(): Matrix<T> {
return this.getFeature<TransposedFeature<T>>()?.original ?: VirtualMatrix( return getFeature<TransposedFeature<T>>()?.original ?: VirtualMatrix(
this.colNum, colNum,
this.rowNum, rowNum,
setOf(TransposedFeature(this)) setOf(TransposedFeature(this))
) { i, j -> get(j, i) } ) { i, j -> get(j, i) }
} }
infix fun Matrix<Double>.dot(other: Matrix<Double>): Matrix<Double> = with(MatrixContext.real) { dot(other) } public infix fun Matrix<Double>.dot(other: Matrix<Double>): Matrix<Double> = with(MatrixContext.real) { dot(other) }

View File

@ -7,19 +7,20 @@ import scientifik.kmath.operations.invoke
import scientifik.kmath.structures.BufferAccessor2D import scientifik.kmath.structures.BufferAccessor2D
import scientifik.kmath.structures.Matrix import scientifik.kmath.structures.Matrix
import scientifik.kmath.structures.Structure2D import scientifik.kmath.structures.Structure2D
import kotlin.contracts.contract
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
* Common implementation of [LUPDecompositionFeature] * Common implementation of [LUPDecompositionFeature]
*/ */
class LUPDecomposition<T : Any>( public class LUPDecomposition<T : Any>(
val context: GenericMatrixContext<T, out Field<T>>, public val context: GenericMatrixContext<T, out Field<T>>,
val lu: Structure2D<T>, public val lu: Structure2D<T>,
val pivot: IntArray, public val pivot: IntArray,
private val even: Boolean private val even: Boolean
) : LUPDecompositionFeature<T>, DeterminantFeature<T> { ) : LUPDecompositionFeature<T>, DeterminantFeature<T> {
public val elementContext: Field<T>
val elementContext: Field<T> get() = context.elementContext get() = context.elementContext
/** /**
* Returns the matrix L of the decomposition. * Returns the matrix L of the decomposition.
@ -44,7 +45,6 @@ class LUPDecomposition<T : Any>(
if (j >= i) lu[i, j] else elementContext.zero if (j >= i) lu[i, j] else elementContext.zero
} }
/** /**
* Returns the P rows permutation matrix. * Returns the P rows permutation matrix.
* *
@ -55,7 +55,6 @@ class LUPDecomposition<T : Any>(
if (j == pivot[i]) elementContext.one else elementContext.zero if (j == pivot[i]) elementContext.one else elementContext.zero
} }
/** /**
* Return the determinant of the matrix * Return the determinant of the matrix
* @return determinant of the matrix * @return determinant of the matrix
@ -66,22 +65,19 @@ class LUPDecomposition<T : Any>(
} }
fun <T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.abs(value: T): T = public fun <T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.abs(value: T): T =
if (value > elementContext.zero) value else elementContext { -value } if (value > elementContext.zero) value else elementContext { -value }
/** /**
* Create a lup decomposition of generic matrix * Create a lup decomposition of generic matrix
*/ */
fun <T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.lup( public inline fun <T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.lup(
type: KClass<T>, type: KClass<T>,
matrix: Matrix<T>, matrix: Matrix<T>,
checkSingular: (T) -> Boolean checkSingular: (T) -> Boolean
): LUPDecomposition<T> { ): LUPDecomposition<T> {
if (matrix.rowNum != matrix.colNum) { contract { callsInPlace(checkSingular) }
error("LU decomposition supports only square matrices") require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" }
}
val m = matrix.colNum val m = matrix.colNum
val pivot = IntArray(matrix.rowNum) val pivot = IntArray(matrix.rowNum)
@ -154,15 +150,18 @@ fun <T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.lup(
} }
} }
inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.lup( public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.lup(
matrix: Matrix<T>, matrix: Matrix<T>,
noinline checkSingular: (T) -> Boolean checkSingular: (T) -> Boolean
): LUPDecomposition<T> = lup(T::class, matrix, checkSingular) ): LUPDecomposition<T> {
contract { callsInPlace(checkSingular) }
return lup(T::class, matrix, checkSingular)
}
fun GenericMatrixContext<Double, RealField>.lup(matrix: Matrix<Double>): LUPDecomposition<Double> = public fun GenericMatrixContext<Double, RealField>.lup(matrix: Matrix<Double>): LUPDecomposition<Double> =
lup(Double::class, matrix) { it < 1e-11 } lup(Double::class, matrix) { it < 1e-11 }
fun <T : Any> LUPDecomposition<T>.solve(type: KClass<T>, matrix: Matrix<T>): Matrix<T> { public fun <T : Any> LUPDecomposition<T>.solve(type: KClass<T>, matrix: Matrix<T>): Matrix<T> {
require(matrix.rowNum == pivot.size) { "Matrix dimension mismatch. Expected ${pivot.size}, but got ${matrix.colNum}" } require(matrix.rowNum == pivot.size) { "Matrix dimension mismatch. Expected ${pivot.size}, but got ${matrix.colNum}" }
BufferAccessor2D(type, matrix.rowNum, matrix.colNum).run { BufferAccessor2D(type, matrix.rowNum, matrix.colNum).run {
@ -207,27 +206,31 @@ fun <T : Any> LUPDecomposition<T>.solve(type: KClass<T>, matrix: Matrix<T>): Mat
} }
} }
inline fun <reified T : Any> LUPDecomposition<T>.solve(matrix: Matrix<T>): Matrix<T> = solve(T::class, matrix) public inline fun <reified T : Any> LUPDecomposition<T>.solve(matrix: Matrix<T>): Matrix<T> = solve(T::class, matrix)
/** /**
* Solve a linear equation **a*x = b** * Solve a linear equation **a*x = b**
*/ */
inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.solve( public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.solve(
a: Matrix<T>, a: Matrix<T>,
b: Matrix<T>, b: Matrix<T>,
noinline checkSingular: (T) -> Boolean checkSingular: (T) -> Boolean
): Matrix<T> { ): Matrix<T> {
contract { callsInPlace(checkSingular) }
// Use existing decomposition if it is provided by matrix // Use existing decomposition if it is provided by matrix
val decomposition = a.getFeature() ?: lup(T::class, a, checkSingular) val decomposition = a.getFeature() ?: lup(T::class, a, checkSingular)
return decomposition.solve(T::class, b) return decomposition.solve(T::class, b)
} }
fun RealMatrixContext.solve(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> = solve(a, b) { it < 1e-11 } public fun RealMatrixContext.solve(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> = solve(a, b) { it < 1e-11 }
inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.inverse( public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F>.inverse(
matrix: Matrix<T>, matrix: Matrix<T>,
noinline checkSingular: (T) -> Boolean checkSingular: (T) -> Boolean
): Matrix<T> = solve(matrix, one(matrix.rowNum, matrix.colNum), checkSingular) ): Matrix<T> {
contract { callsInPlace(checkSingular) }
return solve(matrix, one(matrix.rowNum, matrix.colNum), checkSingular)
}
fun RealMatrixContext.inverse(matrix: Matrix<Double>): Matrix<Double> = public fun RealMatrixContext.inverse(matrix: Matrix<Double>): Matrix<Double> =
solve(matrix, one(matrix.rowNum, matrix.colNum)) { it < 1e-11 } solve(matrix, one(matrix.rowNum, matrix.colNum)) { it < 1e-11 }

View File

@ -4,25 +4,25 @@ import scientifik.kmath.structures.Buffer
import scientifik.kmath.structures.Matrix import scientifik.kmath.structures.Matrix
import scientifik.kmath.structures.VirtualBuffer import scientifik.kmath.structures.VirtualBuffer
typealias Point<T> = Buffer<T> public typealias Point<T> = Buffer<T>
/** /**
* A group of methods to resolve equation A dot X = B, where A and B are matrices or vectors * A group of methods to resolve equation A dot X = B, where A and B are matrices or vectors
*/ */
interface LinearSolver<T : Any> { public interface LinearSolver<T : Any> {
fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T> public fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T>
fun solve(a: Matrix<T>, b: Point<T>): Point<T> = solve(a, b.asMatrix()).asPoint() public fun solve(a: Matrix<T>, b: Point<T>): Point<T> = solve(a, b.asMatrix()).asPoint()
fun inverse(a: Matrix<T>): Matrix<T> public fun inverse(a: Matrix<T>): Matrix<T>
} }
/** /**
* Convert matrix to vector if it is possible * Convert matrix to vector if it is possible
*/ */
fun <T : Any> Matrix<T>.asPoint(): Point<T> = public fun <T : Any> Matrix<T>.asPoint(): Point<T> =
if (this.colNum == 1) { if (this.colNum == 1) {
VirtualBuffer(rowNum) { get(it, 0) } VirtualBuffer(rowNum) { get(it, 0) }
} else { } else {
error("Can't convert matrix with more than one column to vector") error("Can't convert matrix with more than one column to vector")
} }
fun <T : Any> Point<T>.asMatrix(): VirtualMatrix<T> = VirtualMatrix(size, 1) { i, _ -> get(i) } public fun <T : Any> Point<T>.asMatrix(): VirtualMatrix<T> = VirtualMatrix(size, 1) { i, _ -> get(i) }

View File

@ -5,8 +5,8 @@ import scientifik.kmath.structures.BufferFactory
import scientifik.kmath.structures.Structure2D import scientifik.kmath.structures.Structure2D
import scientifik.kmath.structures.asBuffer import scientifik.kmath.structures.asBuffer
class MatrixBuilder(val rows: Int, val columns: Int) { public class MatrixBuilder(public val rows: Int, public val columns: Int) {
operator fun <T : Any> invoke(vararg elements: T): FeaturedMatrix<T> { public operator fun <T : Any> invoke(vararg elements: T): FeaturedMatrix<T> {
require(rows * columns == elements.size) { "The number of elements ${elements.size} is not equal $rows * $columns" } require(rows * columns == elements.size) { "The number of elements ${elements.size} is not equal $rows * $columns" }
val buffer = elements.asBuffer() val buffer = elements.asBuffer()
return BufferMatrix(rows, columns, buffer) return BufferMatrix(rows, columns, buffer)
@ -15,14 +15,14 @@ class MatrixBuilder(val rows: Int, val columns: Int) {
//TODO add specific matrix builder functions like diagonal, etc //TODO add specific matrix builder functions like diagonal, etc
} }
fun Structure2D.Companion.build(rows: Int, columns: Int): MatrixBuilder = MatrixBuilder(rows, columns) public fun Structure2D.Companion.build(rows: Int, columns: Int): MatrixBuilder = MatrixBuilder(rows, columns)
fun <T : Any> Structure2D.Companion.row(vararg values: T): FeaturedMatrix<T> { public fun <T : Any> Structure2D.Companion.row(vararg values: T): FeaturedMatrix<T> {
val buffer = values.asBuffer() val buffer = values.asBuffer()
return BufferMatrix(1, values.size, buffer) return BufferMatrix(1, values.size, buffer)
} }
inline fun <reified T : Any> Structure2D.Companion.row( public inline fun <reified T : Any> Structure2D.Companion.row(
size: Int, size: Int,
factory: BufferFactory<T> = Buffer.Companion::auto, factory: BufferFactory<T> = Buffer.Companion::auto,
noinline builder: (Int) -> T noinline builder: (Int) -> T
@ -31,12 +31,12 @@ inline fun <reified T : Any> Structure2D.Companion.row(
return BufferMatrix(1, size, buffer) return BufferMatrix(1, size, buffer)
} }
fun <T : Any> Structure2D.Companion.column(vararg values: T): FeaturedMatrix<T> { public fun <T : Any> Structure2D.Companion.column(vararg values: T): FeaturedMatrix<T> {
val buffer = values.asBuffer() val buffer = values.asBuffer()
return BufferMatrix(values.size, 1, buffer) return BufferMatrix(values.size, 1, buffer)
} }
inline fun <reified T : Any> Structure2D.Companion.column( public inline fun <reified T : Any> Structure2D.Companion.column(
size: Int, size: Int,
factory: BufferFactory<T> = Buffer.Companion::auto, factory: BufferFactory<T> = Buffer.Companion::auto,
noinline builder: (Int) -> T noinline builder: (Int) -> T

View File

@ -12,30 +12,31 @@ import scientifik.kmath.structures.asSequence
/** /**
* Basic operations on matrices. Operates on [Matrix] * Basic operations on matrices. Operates on [Matrix]
*/ */
interface MatrixContext<T : Any> : SpaceOperations<Matrix<T>> { public interface MatrixContext<T : Any> : SpaceOperations<Matrix<T>> {
/** /**
* Produce a matrix with this context and given dimensions * Produce a matrix with this context and given dimensions
*/ */
fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): Matrix<T> public fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): Matrix<T>
infix fun Matrix<T>.dot(other: Matrix<T>): Matrix<T> public infix fun Matrix<T>.dot(other: Matrix<T>): Matrix<T>
infix fun Matrix<T>.dot(vector: Point<T>): Point<T> public infix fun Matrix<T>.dot(vector: Point<T>): Point<T>
operator fun Matrix<T>.times(value: T): Matrix<T> public operator fun Matrix<T>.times(value: T): Matrix<T>
operator fun T.times(m: Matrix<T>): Matrix<T> = m * this public operator fun T.times(m: Matrix<T>): Matrix<T> = m * this
companion object { public companion object {
/** /**
* Non-boxing double matrix * Non-boxing double matrix
*/ */
val real: RealMatrixContext = RealMatrixContext public val real: RealMatrixContext
get() = RealMatrixContext
/** /**
* A structured matrix with custom buffer * A structured matrix with custom buffer
*/ */
fun <T : Any, R : Ring<T>> buffered( public fun <T : Any, R : Ring<T>> buffered(
ring: R, ring: R,
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing bufferFactory: BufferFactory<T> = Buffer.Companion::boxing
): GenericMatrixContext<T, R> = BufferMatrixContext(ring, bufferFactory) ): GenericMatrixContext<T, R> = BufferMatrixContext(ring, bufferFactory)
@ -43,21 +44,21 @@ interface MatrixContext<T : Any> : SpaceOperations<Matrix<T>> {
/** /**
* Automatic buffered matrix, unboxed if it is possible * Automatic buffered matrix, unboxed if it is possible
*/ */
inline fun <reified T : Any, R : Ring<T>> auto(ring: R): GenericMatrixContext<T, R> = public inline fun <reified T : Any, R : Ring<T>> auto(ring: R): GenericMatrixContext<T, R> =
buffered(ring, Buffer.Companion::auto) buffered(ring, Buffer.Companion::auto)
} }
} }
interface GenericMatrixContext<T : Any, R : Ring<T>> : MatrixContext<T> { public interface GenericMatrixContext<T : Any, R : Ring<T>> : MatrixContext<T> {
/** /**
* The ring context for matrix elements * The ring context for matrix elements
*/ */
val elementContext: R public val elementContext: R
/** /**
* Produce a point compatible with matrix space * Produce a point compatible with matrix space
*/ */
fun point(size: Int, initializer: (Int) -> T): Point<T> public fun point(size: Int, initializer: (Int) -> T): Point<T>
override infix fun Matrix<T>.dot(other: Matrix<T>): Matrix<T> { override infix fun Matrix<T>.dot(other: Matrix<T>): Matrix<T> {
//TODO add typed error //TODO add typed error
@ -102,7 +103,7 @@ interface GenericMatrixContext<T : Any, R : Ring<T>> : MatrixContext<T> {
override fun multiply(a: Matrix<T>, k: Number): Matrix<T> = override fun multiply(a: Matrix<T>, k: Number): Matrix<T> =
produce(a.rowNum, a.colNum) { i, j -> elementContext { a[i, j] * k } } produce(a.rowNum, a.colNum) { i, j -> elementContext { a[i, j] * k } }
operator fun Number.times(matrix: FeaturedMatrix<T>): Matrix<T> = matrix * this public operator fun Number.times(matrix: FeaturedMatrix<T>): Matrix<T> = matrix * this
override operator fun Matrix<T>.times(value: T): Matrix<T> = override operator fun Matrix<T>.times(value: T): Matrix<T> =
produce(rowNum, colNum) { i, j -> elementContext { get(i, j) * value } } produce(rowNum, colNum) { i, j -> elementContext { get(i, j) * value } }

View File

@ -4,59 +4,59 @@ package scientifik.kmath.linear
* A marker interface representing some matrix feature like diagonal, sparse, zero, etc. Features used to optimize matrix * A marker interface representing some matrix feature like diagonal, sparse, zero, etc. Features used to optimize matrix
* operations performance in some cases. * operations performance in some cases.
*/ */
interface MatrixFeature public interface MatrixFeature
/** /**
* The matrix with this feature is considered to have only diagonal non-null elements * The matrix with this feature is considered to have only diagonal non-null elements
*/ */
object DiagonalFeature : MatrixFeature public object DiagonalFeature : MatrixFeature
/** /**
* Matrix with this feature has all zero elements * Matrix with this feature has all zero elements
*/ */
object ZeroFeature : MatrixFeature public object ZeroFeature : MatrixFeature
/** /**
* Matrix with this feature have unit elements on diagonal and zero elements in all other places * Matrix with this feature have unit elements on diagonal and zero elements in all other places
*/ */
object UnitFeature : MatrixFeature public object UnitFeature : MatrixFeature
/** /**
* Inverted matrix feature * Inverted matrix feature
*/ */
interface InverseMatrixFeature<T : Any> : MatrixFeature { public interface InverseMatrixFeature<T : Any> : MatrixFeature {
val inverse: FeaturedMatrix<T> public val inverse: FeaturedMatrix<T>
} }
/** /**
* A determinant container * A determinant container
*/ */
interface DeterminantFeature<T : Any> : MatrixFeature { public interface DeterminantFeature<T : Any> : MatrixFeature {
val determinant: T public val determinant: T
} }
@Suppress("FunctionName") @Suppress("FunctionName")
fun <T : Any> DeterminantFeature(determinant: T): DeterminantFeature<T> = object : DeterminantFeature<T> { public fun <T : Any> DeterminantFeature(determinant: T): DeterminantFeature<T> = object : DeterminantFeature<T> {
override val determinant: T = determinant override val determinant: T = determinant
} }
/** /**
* Lower triangular matrix * Lower triangular matrix
*/ */
object LFeature : MatrixFeature public object LFeature : MatrixFeature
/** /**
* Upper triangular feature * Upper triangular feature
*/ */
object UFeature : MatrixFeature public object UFeature : MatrixFeature
/** /**
* TODO add documentation * TODO add documentation
*/ */
interface LUPDecompositionFeature<T : Any> : MatrixFeature { public interface LUPDecompositionFeature<T : Any> : MatrixFeature {
val l: FeaturedMatrix<T> public val l: FeaturedMatrix<T>
val u: FeaturedMatrix<T> public val u: FeaturedMatrix<T>
val p: FeaturedMatrix<T> public val p: FeaturedMatrix<T>
} }
//TODO add sparse matrix feature //TODO add sparse matrix feature

View File

@ -10,12 +10,12 @@ import scientifik.kmath.structures.BufferFactory
* A linear space for vectors. * A linear space for vectors.
* Could be used on any point-like structure * Could be used on any point-like structure
*/ */
interface VectorSpace<T : Any, S : Space<T>> : Space<Point<T>> { public interface VectorSpace<T : Any, S : Space<T>> : Space<Point<T>> {
val size: Int public val size: Int
val space: S public val space: S
override val zero: Point<T> get() = produce { space.zero } override val zero: Point<T> get() = produce { space.zero }
fun produce(initializer: (Int) -> T): Point<T> public fun produce(initializer: (Int) -> T): Point<T>
/** /**
* Produce a space-element of this vector space for expressions * Produce a space-element of this vector space for expressions
@ -28,13 +28,13 @@ interface VectorSpace<T : Any, S : Space<T>> : Space<Point<T>> {
//TODO add basis //TODO add basis
companion object { public companion object {
private val realSpaceCache: MutableMap<Int, BufferVectorSpace<Double, RealField>> = hashMapOf() private val realSpaceCache: MutableMap<Int, BufferVectorSpace<Double, RealField>> = hashMapOf()
/** /**
* Non-boxing double vector space * Non-boxing double vector space
*/ */
fun real(size: Int): BufferVectorSpace<Double, RealField> = realSpaceCache.getOrPut(size) { public fun real(size: Int): BufferVectorSpace<Double, RealField> = realSpaceCache.getOrPut(size) {
BufferVectorSpace( BufferVectorSpace(
size, size,
RealField, RealField,
@ -45,7 +45,7 @@ interface VectorSpace<T : Any, S : Space<T>> : Space<Point<T>> {
/** /**
* A structured vector space with custom buffer * A structured vector space with custom buffer
*/ */
fun <T : Any, S : Space<T>> buffered( public fun <T : Any, S : Space<T>> buffered(
size: Int, size: Int,
space: S, space: S,
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing bufferFactory: BufferFactory<T> = Buffer.Companion::boxing
@ -54,16 +54,16 @@ interface VectorSpace<T : Any, S : Space<T>> : Space<Point<T>> {
/** /**
* Automatic buffered vector, unboxed if it is possible * Automatic buffered vector, unboxed if it is possible
*/ */
inline fun <reified T : Any, S : Space<T>> auto(size: Int, space: S): VectorSpace<T, S> = public inline fun <reified T : Any, S : Space<T>> auto(size: Int, space: S): VectorSpace<T, S> =
buffered(size, space, Buffer.Companion::auto) buffered(size, space, Buffer.Companion::auto)
} }
} }
class BufferVectorSpace<T : Any, S : Space<T>>( public class BufferVectorSpace<T : Any, S : Space<T>>(
override val size: Int, override val size: Int,
override val space: S, override val space: S,
val bufferFactory: BufferFactory<T> public val bufferFactory: BufferFactory<T>
) : VectorSpace<T, S> { ) : VectorSpace<T, S> {
override fun produce(initializer: (Int) -> T): Buffer<T> = bufferFactory(size, initializer) override fun produce(initializer: (Int) -> T): Buffer<T> = bufferFactory(size, initializer)
//override fun produceElement(initializer: (Int) -> T): Vector<T, S> = BufferVector(this, produce(initializer)) //override fun produceElement(initializer: (Int) -> T): Vector<T, S> = BufferVector(this, produce(initializer))

View File

@ -2,14 +2,18 @@ package scientifik.kmath.linear
import scientifik.kmath.structures.Matrix import scientifik.kmath.structures.Matrix
class VirtualMatrix<T : Any>( public class VirtualMatrix<T : Any>(
override val rowNum: Int, override val rowNum: Int,
override val colNum: Int, override val colNum: Int,
override val features: Set<MatrixFeature> = emptySet(), override val features: Set<MatrixFeature> = emptySet(),
val generator: (i: Int, j: Int) -> T public val generator: (i: Int, j: Int) -> T
) : FeaturedMatrix<T> { ) : FeaturedMatrix<T> {
public constructor(
constructor(rowNum: Int, colNum: Int, vararg features: MatrixFeature, generator: (i: Int, j: Int) -> T) : this( rowNum: Int,
colNum: Int,
vararg features: MatrixFeature,
generator: (i: Int, j: Int) -> T
) : this(
rowNum, rowNum,
colNum, colNum,
setOf(*features), setOf(*features),
@ -42,18 +46,15 @@ class VirtualMatrix<T : Any>(
} }
companion object { public companion object {
/** /**
* Wrap a matrix adding additional features to it * Wrap a matrix adding additional features to it
*/ */
fun <T : Any> wrap(matrix: Matrix<T>, vararg features: MatrixFeature): FeaturedMatrix<T> { public fun <T : Any> wrap(matrix: Matrix<T>, vararg features: MatrixFeature): FeaturedMatrix<T> {
return if (matrix is VirtualMatrix) { return if (matrix is VirtualMatrix)
VirtualMatrix(matrix.rowNum, matrix.colNum, matrix.features + features, matrix.generator) VirtualMatrix(matrix.rowNum, matrix.colNum, matrix.features + features, matrix.generator)
} else { else
VirtualMatrix(matrix.rowNum, matrix.colNum, matrix.features + features) { i, j -> VirtualMatrix(matrix.rowNum, matrix.colNum, matrix.features + features) { i, j -> matrix[i, j] }
matrix[i, j]
}
}
} }
} }
} }

View File

@ -19,24 +19,24 @@ import kotlin.contracts.contract
* Differentiable variable with value and derivative of differentiation ([deriv]) result * Differentiable variable with value and derivative of differentiation ([deriv]) result
* with respect to this variable. * with respect to this variable.
*/ */
open class Variable<T : Any>(val value: T) public open class Variable<T : Any>(public val value: T)
class DerivationResult<T : Any>( public class DerivationResult<T : Any>(
value: T, value: T,
val deriv: Map<Variable<T>, T>, public val deriv: Map<Variable<T>, T>,
val context: Field<T> public val context: Field<T>
) : Variable<T>(value) { ) : Variable<T>(value) {
fun deriv(variable: Variable<T>): T = deriv[variable] ?: context.zero public fun deriv(variable: Variable<T>): T = deriv[variable] ?: context.zero
/** /**
* compute divergence * compute divergence
*/ */
fun div(): T = context { sum(deriv.values) } public fun div(): T = context { sum(deriv.values) }
/** /**
* Compute a gradient for variables in given order * Compute a gradient for variables in given order
*/ */
fun grad(vararg variables: Variable<T>): Point<T> { public fun grad(vararg variables: Variable<T>): Point<T> {
check(variables.isNotEmpty()) { "Variable order is not provided for gradient construction" } check(variables.isNotEmpty()) { "Variable order is not provided for gradient construction" }
return variables.map(::deriv).asBuffer() return variables.map(::deriv).asBuffer()
} }
@ -55,7 +55,7 @@ class DerivationResult<T : Any>(
* assertEquals(9.0, x.d) // dy/dx * assertEquals(9.0, x.d) // dy/dx
* ``` * ```
*/ */
inline fun <T : Any, F : Field<T>> F.deriv(body: AutoDiffField<T, F>.() -> Variable<T>): DerivationResult<T> { public inline fun <T : Any, F : Field<T>> F.deriv(body: AutoDiffField<T, F>.() -> Variable<T>): DerivationResult<T> {
contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) }
return (AutoDiffContext(this)) { return (AutoDiffContext(this)) {
@ -67,14 +67,14 @@ inline fun <T : Any, F : Field<T>> F.deriv(body: AutoDiffField<T, F>.() -> Varia
} }
abstract class AutoDiffField<T : Any, F : Field<T>> : Field<Variable<T>> { public abstract class AutoDiffField<T : Any, F : Field<T>> : Field<Variable<T>> {
abstract val context: F public abstract val context: F
/** /**
* A variable accessing inner state of derivatives. * A variable accessing inner state of derivatives.
* Use this function in inner builders to avoid creating additional derivative bindings * Use this function in inner builders to avoid creating additional derivative bindings
*/ */
abstract var Variable<T>.d: T public abstract var Variable<T>.d: T
/** /**
* Performs update of derivative after the rest of the formula in the back-pass. * Performs update of derivative after the rest of the formula in the back-pass.
@ -87,11 +87,11 @@ abstract class AutoDiffField<T : Any, F : Field<T>> : Field<Variable<T>> {
* } * }
* ``` * ```
*/ */
abstract fun <R> derive(value: R, block: F.(R) -> Unit): R public abstract fun <R> derive(value: R, block: F.(R) -> Unit): R
abstract fun variable(value: T): Variable<T> public abstract fun variable(value: T): Variable<T>
inline fun variable(block: F.() -> T): Variable<T> = variable(context.block()) public inline fun variable(block: F.() -> T): Variable<T> = variable(context.block())
// Overloads for Double constants // Overloads for Double constants
@ -153,7 +153,6 @@ internal class AutoDiffContext<T : Any, F : Field<T>>(override val context: F) :
// Basic math (+, -, *, /) // Basic math (+, -, *, /)
override fun add(a: Variable<T>, b: Variable<T>): Variable<T> = derive(variable { a.value + b.value }) { z -> override fun add(a: Variable<T>, b: Variable<T>): Variable<T> = derive(variable { a.value + b.value }) { z ->
a.d += z.d a.d += z.d
b.d += z.d b.d += z.d
@ -177,35 +176,36 @@ internal class AutoDiffContext<T : Any, F : Field<T>>(override val context: F) :
// Extensions for differentiation of various basic mathematical functions // Extensions for differentiation of various basic mathematical functions
// x ^ 2 // x ^ 2
fun <T : Any, F : Field<T>> AutoDiffField<T, F>.sqr(x: Variable<T>): Variable<T> = public fun <T : Any, F : Field<T>> AutoDiffField<T, F>.sqr(x: Variable<T>): Variable<T> =
derive(variable { x.value * x.value }) { z -> x.d += z.d * 2 * x.value } derive(variable { x.value * x.value }) { z -> x.d += z.d * 2 * x.value }
// x ^ 1/2 // x ^ 1/2
fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.sqrt(x: Variable<T>): Variable<T> = public fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.sqrt(x: Variable<T>): Variable<T> =
derive(variable { sqrt(x.value) }) { z -> x.d += z.d * 0.5 / z.value } derive(variable { sqrt(x.value) }) { z -> x.d += z.d * 0.5 / z.value }
// x ^ y (const) // x ^ y (const)
fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.pow(x: Variable<T>, y: Double): Variable<T> = public fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.pow(x: Variable<T>, y: Double): Variable<T> =
derive(variable { power(x.value, y) }) { z -> x.d += z.d * y * power(x.value, y - 1) } derive(variable { power(x.value, y) }) { z -> x.d += z.d * y * power(x.value, y - 1) }
fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.pow(x: Variable<T>, y: Int): Variable<T> = pow(x, y.toDouble()) public fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.pow(x: Variable<T>, y: Int): Variable<T> =
pow(x, y.toDouble())
// exp(x) // exp(x)
fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.exp(x: Variable<T>): Variable<T> = public fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.exp(x: Variable<T>): Variable<T> =
derive(variable { exp(x.value) }) { z -> x.d += z.d * z.value } derive(variable { exp(x.value) }) { z -> x.d += z.d * z.value }
// ln(x) // ln(x)
fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.ln(x: Variable<T>): Variable<T> = public fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.ln(x: Variable<T>): Variable<T> =
derive(variable { ln(x.value) }) { z -> x.d += z.d / x.value } derive(variable { ln(x.value) }) { z -> x.d += z.d / x.value }
// x ^ y (any) // x ^ y (any)
fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.pow(x: Variable<T>, y: Variable<T>): Variable<T> = public fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.pow(x: Variable<T>, y: Variable<T>): Variable<T> =
exp(y * ln(x)) exp(y * ln(x))
// sin(x) // sin(x)
fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.sin(x: Variable<T>): Variable<T> = public fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.sin(x: Variable<T>): Variable<T> =
derive(variable { sin(x.value) }) { z -> x.d += z.d * cos(x.value) } derive(variable { sin(x.value) }) { z -> x.d += z.d * cos(x.value) }
// cos(x) // cos(x)
fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.cos(x: Variable<T>): Variable<T> = public fun <T : Any, F : ExtendedField<T>> AutoDiffField<T, F>.cos(x: Variable<T>): Variable<T> =
derive(variable { cos(x.value) }) { z -> x.d -= z.d * sin(x.value) } derive(variable { cos(x.value) }) { z -> x.d -= z.d * sin(x.value) }

View File

@ -10,17 +10,21 @@ import kotlin.math.abs
* *
* If step is negative, the same goes from upper boundary downwards * If step is negative, the same goes from upper boundary downwards
*/ */
fun ClosedFloatingPointRange<Double>.toSequenceWithStep(step: Double): Sequence<Double> = when { public fun ClosedFloatingPointRange<Double>.toSequenceWithStep(step: Double): Sequence<Double> = when {
step == 0.0 -> error("Zero step in double progression") step == 0.0 -> error("Zero step in double progression")
step > 0 -> sequence { step > 0 -> sequence {
var current = start var current = start
while (current <= endInclusive) { while (current <= endInclusive) {
yield(current) yield(current)
current += step current += step
} }
} }
else -> sequence { else -> sequence {
var current = endInclusive var current = endInclusive
while (current >= start) { while (current >= start) {
yield(current) yield(current)
current += step current += step
@ -31,7 +35,7 @@ fun ClosedFloatingPointRange<Double>.toSequenceWithStep(step: Double): Sequence<
/** /**
* Convert double range to sequence with the fixed number of points * Convert double range to sequence with the fixed number of points
*/ */
fun ClosedFloatingPointRange<Double>.toSequenceWithPoints(numPoints: Int): Sequence<Double> { public fun ClosedFloatingPointRange<Double>.toSequenceWithPoints(numPoints: Int): Sequence<Double> {
require(numPoints > 1) { "The number of points should be more than 2" } require(numPoints > 1) { "The number of points should be more than 2" }
return toSequenceWithStep(abs(endInclusive - start) / (numPoints - 1)) return toSequenceWithStep(abs(endInclusive - start) / (numPoints - 1))
} }
@ -40,7 +44,7 @@ fun ClosedFloatingPointRange<Double>.toSequenceWithPoints(numPoints: Int): Seque
* Convert double range to array of evenly spaced doubles, where the size of array equals [numPoints] * Convert double range to array of evenly spaced doubles, where the size of array equals [numPoints]
*/ */
@Deprecated("Replace by 'toSequenceWithPoints'") @Deprecated("Replace by 'toSequenceWithPoints'")
fun ClosedFloatingPointRange<Double>.toGrid(numPoints: Int): DoubleArray { public fun ClosedFloatingPointRange<Double>.toGrid(numPoints: Int): DoubleArray {
require(numPoints >= 2) { "Can't create generic grid with less than two points" } require(numPoints >= 2) { "Can't create generic grid with less than two points" }
return DoubleArray(numPoints) { i -> start + (endInclusive - start) / (numPoints - 1) * i } return DoubleArray(numPoints) { i -> start + (endInclusive - start) / (numPoints - 1) * i }
} }

View File

@ -2,7 +2,6 @@ package scientifik.kmath.misc
import scientifik.kmath.operations.Space import scientifik.kmath.operations.Space
import scientifik.kmath.operations.invoke import scientifik.kmath.operations.invoke
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
@ -13,7 +12,7 @@ import kotlin.jvm.JvmName
* @param R the type of resulting iterable. * @param R the type of resulting iterable.
* @param initial lazy evaluated. * @param initial lazy evaluated.
*/ */
inline fun <T, R> Iterator<T>.cumulative(initial: R, crossinline operation: (R, T) -> R): Iterator<R> { public inline fun <T, R> Iterator<T>.cumulative(initial: R, crossinline operation: (R, T) -> R): Iterator<R> {
contract { callsInPlace(operation) } contract { callsInPlace(operation) }
return object : Iterator<R> { return object : Iterator<R> {
@ -28,14 +27,13 @@ inline fun <T, R> Iterator<T>.cumulative(initial: R, crossinline operation: (R,
} }
} }
inline fun <T, R> Iterable<T>.cumulative(initial: R, crossinline operation: (R, T) -> R): Iterable<R> = public inline fun <T, R> Iterable<T>.cumulative(initial: R, crossinline operation: (R, T) -> R): Iterable<R> =
Iterable { this@cumulative.iterator().cumulative(initial, operation) } Iterable { this@cumulative.iterator().cumulative(initial, operation) }
inline fun <T, R> Sequence<T>.cumulative(initial: R, crossinline operation: (R, T) -> R): Sequence<R> = Sequence { public inline fun <T, R> Sequence<T>.cumulative(initial: R, crossinline operation: (R, T) -> R): Sequence<R> =
this@cumulative.iterator().cumulative(initial, operation) Sequence { this@cumulative.iterator().cumulative(initial, operation) }
}
fun <T, R> List<T>.cumulative(initial: R, operation: (R, T) -> R): List<R> = public fun <T, R> List<T>.cumulative(initial: R, operation: (R, T) -> R): List<R> =
iterator().cumulative(initial, operation).asSequence().toList() iterator().cumulative(initial, operation).asSequence().toList()
//Cumulative sum //Cumulative sum
@ -43,38 +41,38 @@ fun <T, R> List<T>.cumulative(initial: R, operation: (R, T) -> R): List<R> =
/** /**
* Cumulative sum with custom space * Cumulative sum with custom space
*/ */
fun <T> Iterable<T>.cumulativeSum(space: Space<T>): Iterable<T> = public fun <T> Iterable<T>.cumulativeSum(space: Space<T>): Iterable<T> =
space { cumulative(zero) { element: T, sum: T -> sum + element } } space { cumulative(zero) { element: T, sum: T -> sum + element } }
@JvmName("cumulativeSumOfDouble") @JvmName("cumulativeSumOfDouble")
fun Iterable<Double>.cumulativeSum(): Iterable<Double> = cumulative(0.0) { element, sum -> sum + element } public fun Iterable<Double>.cumulativeSum(): Iterable<Double> = cumulative(0.0) { element, sum -> sum + element }
@JvmName("cumulativeSumOfInt") @JvmName("cumulativeSumOfInt")
fun Iterable<Int>.cumulativeSum(): Iterable<Int> = cumulative(0) { element, sum -> sum + element } public fun Iterable<Int>.cumulativeSum(): Iterable<Int> = cumulative(0) { element, sum -> sum + element }
@JvmName("cumulativeSumOfLong") @JvmName("cumulativeSumOfLong")
fun Iterable<Long>.cumulativeSum(): Iterable<Long> = cumulative(0L) { element, sum -> sum + element } public fun Iterable<Long>.cumulativeSum(): Iterable<Long> = cumulative(0L) { element, sum -> sum + element }
fun <T> Sequence<T>.cumulativeSum(space: Space<T>): Sequence<T> = public fun <T> Sequence<T>.cumulativeSum(space: Space<T>): Sequence<T> =
space { cumulative(zero) { element: T, sum: T -> sum + element } } space { cumulative(zero) { element: T, sum: T -> sum + element } }
@JvmName("cumulativeSumOfDouble") @JvmName("cumulativeSumOfDouble")
fun Sequence<Double>.cumulativeSum(): Sequence<Double> = cumulative(0.0) { element, sum -> sum + element } public fun Sequence<Double>.cumulativeSum(): Sequence<Double> = cumulative(0.0) { element, sum -> sum + element }
@JvmName("cumulativeSumOfInt") @JvmName("cumulativeSumOfInt")
fun Sequence<Int>.cumulativeSum(): Sequence<Int> = cumulative(0) { element, sum -> sum + element } public fun Sequence<Int>.cumulativeSum(): Sequence<Int> = cumulative(0) { element, sum -> sum + element }
@JvmName("cumulativeSumOfLong") @JvmName("cumulativeSumOfLong")
fun Sequence<Long>.cumulativeSum(): Sequence<Long> = cumulative(0L) { element, sum -> sum + element } public fun Sequence<Long>.cumulativeSum(): Sequence<Long> = cumulative(0L) { element, sum -> sum + element }
fun <T> List<T>.cumulativeSum(space: Space<T>): List<T> = public fun <T> List<T>.cumulativeSum(space: Space<T>): List<T> =
space { cumulative(zero) { element: T, sum: T -> sum + element } } space { cumulative(zero) { element: T, sum: T -> sum + element } }
@JvmName("cumulativeSumOfDouble") @JvmName("cumulativeSumOfDouble")
fun List<Double>.cumulativeSum(): List<Double> = cumulative(0.0) { element, sum -> sum + element } public fun List<Double>.cumulativeSum(): List<Double> = cumulative(0.0) { element, sum -> sum + element }
@JvmName("cumulativeSumOfInt") @JvmName("cumulativeSumOfInt")
fun List<Int>.cumulativeSum(): List<Int> = cumulative(0) { element, sum -> sum + element } public fun List<Int>.cumulativeSum(): List<Int> = cumulative(0) { element, sum -> sum + element }
@JvmName("cumulativeSumOfLong") @JvmName("cumulativeSumOfLong")
fun List<Long>.cumulativeSum(): List<Long> = cumulative(0L) { element, sum -> sum + element } public fun List<Long>.cumulativeSum(): List<Long> = cumulative(0L) { element, sum -> sum + element }

View File

@ -4,28 +4,28 @@ package scientifik.kmath.operations
* Stub for DSL the [Algebra] is. * Stub for DSL the [Algebra] is.
*/ */
@DslMarker @DslMarker
annotation class KMathContext public annotation class KMathContext
/** /**
* Represents an algebraic structure. * Represents an algebraic structure.
* *
* @param T the type of element of this structure. * @param T the type of element of this structure.
*/ */
interface Algebra<T> { public interface Algebra<T> {
/** /**
* Wrap raw string or variable * Wrap raw string or variable
*/ */
fun symbol(value: String): T = error("Wrapping of '$value' is not supported in $this") public fun symbol(value: String): T = error("Wrapping of '$value' is not supported in $this")
/** /**
* Dynamic call of unary operation with name [operation] on [arg] * Dynamic call of unary operation with name [operation] on [arg]
*/ */
fun unaryOperation(operation: String, arg: T): T public fun unaryOperation(operation: String, arg: T): T
/** /**
* Dynamic call of binary operation [operation] on [left] and [right] * Dynamic call of binary operation [operation] on [left] and [right]
*/ */
fun binaryOperation(operation: String, left: T, right: T): T public fun binaryOperation(operation: String, left: T, right: T): T
} }
/** /**
@ -33,29 +33,30 @@ interface Algebra<T> {
* *
* @param T the type of element of this structure. * @param T the type of element of this structure.
*/ */
interface NumericAlgebra<T> : Algebra<T> { public interface NumericAlgebra<T> : Algebra<T> {
/** /**
* Wraps a number. * Wraps a number.
*/ */
fun number(value: Number): T public fun number(value: Number): T
/** /**
* Dynamic call of binary operation [operation] on [left] and [right] where left element is [Number]. * Dynamic call of binary operation [operation] on [left] and [right] where left element is [Number].
*/ */
fun leftSideNumberOperation(operation: String, left: Number, right: T): T = public fun leftSideNumberOperation(operation: String, left: Number, right: T): T =
binaryOperation(operation, number(left), right) binaryOperation(operation, number(left), right)
/** /**
* Dynamic call of binary operation [operation] on [left] and [right] where right element is [Number]. * Dynamic call of binary operation [operation] on [left] and [right] where right element is [Number].
*/ */
fun rightSideNumberOperation(operation: String, left: T, right: Number): T = public fun rightSideNumberOperation(operation: String, left: T, right: Number): T =
leftSideNumberOperation(operation, right, left) leftSideNumberOperation(operation, right, left)
} }
/** /**
* Call a block with an [Algebra] as receiver. * Call a block with an [Algebra] as receiver.
*/ */
inline operator fun <A : Algebra<*>, R> A.invoke(block: A.() -> R): R = run(block) // TODO add contract when KT-32313 is fixed
public inline operator fun <A : Algebra<*>, R> A.invoke(block: A.() -> R): R = block()
/** /**
* Represents "semispace", i.e. algebraic structure with associative binary operation called "addition" as well as * Represents "semispace", i.e. algebraic structure with associative binary operation called "addition" as well as
@ -63,7 +64,7 @@ inline operator fun <A : Algebra<*>, R> A.invoke(block: A.() -> R): R = run(bloc
* *
* @param T the type of element of this semispace. * @param T the type of element of this semispace.
*/ */
interface SpaceOperations<T> : Algebra<T> { public interface SpaceOperations<T> : Algebra<T> {
/** /**
* Addition of two elements. * Addition of two elements.
* *
@ -71,7 +72,7 @@ interface SpaceOperations<T> : Algebra<T> {
* @param b the augend. * @param b the augend.
* @return the sum. * @return the sum.
*/ */
fun add(a: T, b: T): T public fun add(a: T, b: T): T
/** /**
* Multiplication of element by scalar. * Multiplication of element by scalar.
@ -80,7 +81,7 @@ interface SpaceOperations<T> : Algebra<T> {
* @param k the multiplicand. * @param k the multiplicand.
* @return the produce. * @return the produce.
*/ */
fun multiply(a: T, k: Number): T public fun multiply(a: T, k: Number): T
// Operations to be performed in this context. Could be moved to extensions in case of KEEP-176 // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176
@ -90,7 +91,7 @@ interface SpaceOperations<T> : Algebra<T> {
* @receiver this value. * @receiver this value.
* @return the additive inverse of this value. * @return the additive inverse of this value.
*/ */
operator fun T.unaryMinus(): T = multiply(this, -1.0) public operator fun T.unaryMinus(): T = multiply(this, -1.0)
/** /**
* Returns this value. * Returns this value.
@ -98,7 +99,7 @@ interface SpaceOperations<T> : Algebra<T> {
* @receiver this value. * @receiver this value.
* @return this value. * @return this value.
*/ */
operator fun T.unaryPlus(): T = this public operator fun T.unaryPlus(): T = this
/** /**
* Addition of two elements. * Addition of two elements.
@ -107,7 +108,7 @@ interface SpaceOperations<T> : Algebra<T> {
* @param b the augend. * @param b the augend.
* @return the sum. * @return the sum.
*/ */
operator fun T.plus(b: T): T = add(this, b) public operator fun T.plus(b: T): T = add(this, b)
/** /**
* Subtraction of two elements. * Subtraction of two elements.
@ -116,7 +117,7 @@ interface SpaceOperations<T> : Algebra<T> {
* @param b the subtrahend. * @param b the subtrahend.
* @return the difference. * @return the difference.
*/ */
operator fun T.minus(b: T): T = add(this, -b) public operator fun T.minus(b: T): T = add(this, -b)
/** /**
* Multiplication of this element by a scalar. * Multiplication of this element by a scalar.
@ -125,7 +126,7 @@ interface SpaceOperations<T> : Algebra<T> {
* @param k the multiplicand. * @param k the multiplicand.
* @return the product. * @return the product.
*/ */
operator fun T.times(k: Number): T = multiply(this, k.toDouble()) public operator fun T.times(k: Number): T = multiply(this, k.toDouble())
/** /**
* Division of this element by scalar. * Division of this element by scalar.
@ -134,7 +135,7 @@ interface SpaceOperations<T> : Algebra<T> {
* @param k the divisor. * @param k the divisor.
* @return the quotient. * @return the quotient.
*/ */
operator fun T.div(k: Number): T = multiply(this, 1.0 / k.toDouble()) public operator fun T.div(k: Number): T = multiply(this, 1.0 / k.toDouble())
/** /**
* Multiplication of this number by element. * Multiplication of this number by element.
@ -143,7 +144,7 @@ interface SpaceOperations<T> : Algebra<T> {
* @param b the multiplicand. * @param b the multiplicand.
* @return the product. * @return the product.
*/ */
operator fun Number.times(b: T): T = b * this public operator fun Number.times(b: T): T = b * this
override fun unaryOperation(operation: String, arg: T): T = when (operation) { override fun unaryOperation(operation: String, arg: T): T = when (operation) {
PLUS_OPERATION -> arg PLUS_OPERATION -> arg
@ -157,18 +158,16 @@ interface SpaceOperations<T> : Algebra<T> {
else -> error("Binary operation $operation not defined in $this") else -> error("Binary operation $operation not defined in $this")
} }
companion object { public companion object {
/** /**
* The identifier of addition. * The identifier of addition.
*/ */
const val PLUS_OPERATION: String = "+" public const val PLUS_OPERATION: String = "+"
/** /**
* The identifier of subtraction (and negation). * The identifier of subtraction (and negation).
*/ */
const val MINUS_OPERATION: String = "-" public const val MINUS_OPERATION: String = "-"
const val NOT_OPERATION: String = "!"
} }
} }
@ -178,11 +177,11 @@ interface SpaceOperations<T> : Algebra<T> {
* *
* @param T the type of element of this group. * @param T the type of element of this group.
*/ */
interface Space<T> : SpaceOperations<T> { public interface Space<T> : SpaceOperations<T> {
/** /**
* The neutral element of addition. * The neutral element of addition.
*/ */
val zero: T public val zero: T
} }
/** /**
@ -191,14 +190,14 @@ interface Space<T> : SpaceOperations<T> {
* *
* @param T the type of element of this semiring. * @param T the type of element of this semiring.
*/ */
interface RingOperations<T> : SpaceOperations<T> { public interface RingOperations<T> : SpaceOperations<T> {
/** /**
* Multiplies two elements. * Multiplies two elements.
* *
* @param a the multiplier. * @param a the multiplier.
* @param b the multiplicand. * @param b the multiplicand.
*/ */
fun multiply(a: T, b: T): T public fun multiply(a: T, b: T): T
/** /**
* Multiplies this element by scalar. * Multiplies this element by scalar.
@ -206,18 +205,18 @@ interface RingOperations<T> : SpaceOperations<T> {
* @receiver the multiplier. * @receiver the multiplier.
* @param b the multiplicand. * @param b the multiplicand.
*/ */
operator fun T.times(b: T): T = multiply(this, b) public operator fun T.times(b: T): T = multiply(this, b)
override fun binaryOperation(operation: String, left: T, right: T): T = when (operation) { override fun binaryOperation(operation: String, left: T, right: T): T = when (operation) {
TIMES_OPERATION -> multiply(left, right) TIMES_OPERATION -> multiply(left, right)
else -> super.binaryOperation(operation, left, right) else -> super.binaryOperation(operation, left, right)
} }
companion object { public companion object {
/** /**
* The identifier of multiplication. * The identifier of multiplication.
*/ */
const val TIMES_OPERATION: String = "*" public const val TIMES_OPERATION: String = "*"
} }
} }
@ -227,11 +226,11 @@ interface RingOperations<T> : SpaceOperations<T> {
* *
* @param T the type of element of this ring. * @param T the type of element of this ring.
*/ */
interface Ring<T> : Space<T>, RingOperations<T>, NumericAlgebra<T> { public interface Ring<T> : Space<T>, RingOperations<T>, NumericAlgebra<T> {
/** /**
* neutral operation for multiplication * neutral operation for multiplication
*/ */
val one: T public val one: T
override fun number(value: Number): T = one * value.toDouble() override fun number(value: Number): T = one * value.toDouble()
@ -255,7 +254,7 @@ interface Ring<T> : Space<T>, RingOperations<T>, NumericAlgebra<T> {
* @receiver the addend. * @receiver the addend.
* @param b the augend. * @param b the augend.
*/ */
operator fun T.plus(b: Number): T = this + number(b) public operator fun T.plus(b: Number): T = this + number(b)
/** /**
* Addition of scalar and element. * Addition of scalar and element.
@ -263,7 +262,7 @@ interface Ring<T> : Space<T>, RingOperations<T>, NumericAlgebra<T> {
* @receiver the addend. * @receiver the addend.
* @param b the augend. * @param b the augend.
*/ */
operator fun Number.plus(b: T): T = b + this public operator fun Number.plus(b: T): T = b + this
/** /**
* Subtraction of element from number. * Subtraction of element from number.
@ -272,7 +271,7 @@ interface Ring<T> : Space<T>, RingOperations<T>, NumericAlgebra<T> {
* @param b the subtrahend. * @param b the subtrahend.
* @receiver the difference. * @receiver the difference.
*/ */
operator fun T.minus(b: Number): T = this - number(b) public operator fun T.minus(b: Number): T = this - number(b)
/** /**
* Subtraction of number from element. * Subtraction of number from element.
@ -281,7 +280,7 @@ interface Ring<T> : Space<T>, RingOperations<T>, NumericAlgebra<T> {
* @param b the subtrahend. * @param b the subtrahend.
* @receiver the difference. * @receiver the difference.
*/ */
operator fun Number.minus(b: T): T = -b + this public operator fun Number.minus(b: T): T = -b + this
} }
/** /**
@ -290,7 +289,7 @@ interface Ring<T> : Space<T>, RingOperations<T>, NumericAlgebra<T> {
* *
* @param T the type of element of this semifield. * @param T the type of element of this semifield.
*/ */
interface FieldOperations<T> : RingOperations<T> { public interface FieldOperations<T> : RingOperations<T> {
/** /**
* Division of two elements. * Division of two elements.
* *
@ -298,7 +297,7 @@ interface FieldOperations<T> : RingOperations<T> {
* @param b the divisor. * @param b the divisor.
* @return the quotient. * @return the quotient.
*/ */
fun divide(a: T, b: T): T public fun divide(a: T, b: T): T
/** /**
* Division of two elements. * Division of two elements.
@ -307,18 +306,18 @@ interface FieldOperations<T> : RingOperations<T> {
* @param b the divisor. * @param b the divisor.
* @return the quotient. * @return the quotient.
*/ */
operator fun T.div(b: T): T = divide(this, b) public operator fun T.div(b: T): T = divide(this, b)
override fun binaryOperation(operation: String, left: T, right: T): T = when (operation) { override fun binaryOperation(operation: String, left: T, right: T): T = when (operation) {
DIV_OPERATION -> divide(left, right) DIV_OPERATION -> divide(left, right)
else -> super.binaryOperation(operation, left, right) else -> super.binaryOperation(operation, left, right)
} }
companion object { public companion object {
/** /**
* The identifier of division. * The identifier of division.
*/ */
const val DIV_OPERATION: String = "/" public const val DIV_OPERATION: String = "/"
} }
} }
@ -328,7 +327,7 @@ interface FieldOperations<T> : RingOperations<T> {
* *
* @param T the type of element of this semifield. * @param T the type of element of this semifield.
*/ */
interface Field<T> : Ring<T>, FieldOperations<T> { public interface Field<T> : Ring<T>, FieldOperations<T> {
/** /**
* Division of element by scalar. * Division of element by scalar.
* *
@ -336,5 +335,5 @@ interface Field<T> : Ring<T>, FieldOperations<T> {
* @param b the divisor. * @param b the divisor.
* @return the quotient. * @return the quotient.
*/ */
operator fun Number.div(b: T): T = this * divide(one, b) public operator fun Number.div(b: T): T = this * divide(one, b)
} }

View File

@ -5,11 +5,11 @@ package scientifik.kmath.operations
* *
* @param C the type of mathematical context for this element. * @param C the type of mathematical context for this element.
*/ */
interface MathElement<C> { public interface MathElement<C> {
/** /**
* The context this element belongs to. * The context this element belongs to.
*/ */
val context: C public val context: C
} }
/** /**
@ -18,16 +18,16 @@ interface MathElement<C> {
* @param T the type wrapped by this wrapper. * @param T the type wrapped by this wrapper.
* @param I the type of this wrapper. * @param I the type of this wrapper.
*/ */
interface MathWrapper<T, I> { public interface MathWrapper<T, I> {
/** /**
* Unwraps [I] to [T]. * Unwraps [I] to [T].
*/ */
fun unwrap(): T public fun unwrap(): T
/** /**
* Wraps [T] to [I]. * Wraps [T] to [I].
*/ */
fun T.wrap(): I public fun T.wrap(): I
} }
/** /**
@ -37,14 +37,14 @@ interface MathWrapper<T, I> {
* @param I self type of the element. Needed for static type checking. * @param I self type of the element. Needed for static type checking.
* @param S the type of space. * @param S the type of space.
*/ */
interface SpaceElement<T, I : SpaceElement<T, I, S>, S : Space<T>> : MathElement<S>, MathWrapper<T, I> { public interface SpaceElement<T, I : SpaceElement<T, I, S>, S : Space<T>> : MathElement<S>, MathWrapper<T, I> {
/** /**
* Adds element to this one. * Adds element to this one.
* *
* @param b the augend. * @param b the augend.
* @return the sum. * @return the sum.
*/ */
operator fun plus(b: T): I = context.add(unwrap(), b).wrap() public operator fun plus(b: T): I = context.add(unwrap(), b).wrap()
/** /**
* Subtracts element from this one. * Subtracts element from this one.
@ -52,7 +52,7 @@ interface SpaceElement<T, I : SpaceElement<T, I, S>, S : Space<T>> : MathElement
* @param b the subtrahend. * @param b the subtrahend.
* @return the difference. * @return the difference.
*/ */
operator fun minus(b: T): I = context.add(unwrap(), context.multiply(b, -1.0)).wrap() public operator fun minus(b: T): I = context.add(unwrap(), context.multiply(b, -1.0)).wrap()
/** /**
* Multiplies this element by number. * Multiplies this element by number.
@ -60,7 +60,7 @@ interface SpaceElement<T, I : SpaceElement<T, I, S>, S : Space<T>> : MathElement
* @param k the multiplicand. * @param k the multiplicand.
* @return the product. * @return the product.
*/ */
operator fun times(k: Number): I = context.multiply(unwrap(), k.toDouble()).wrap() public operator fun times(k: Number): I = context.multiply(unwrap(), k.toDouble()).wrap()
/** /**
* Divides this element by number. * Divides this element by number.
@ -68,7 +68,7 @@ interface SpaceElement<T, I : SpaceElement<T, I, S>, S : Space<T>> : MathElement
* @param k the divisor. * @param k the divisor.
* @return the quotient. * @return the quotient.
*/ */
operator fun div(k: Number): I = context.multiply(unwrap(), 1.0 / k.toDouble()).wrap() public operator fun div(k: Number): I = context.multiply(unwrap(), 1.0 / k.toDouble()).wrap()
} }
/** /**
@ -78,14 +78,14 @@ interface SpaceElement<T, I : SpaceElement<T, I, S>, S : Space<T>> : MathElement
* @param I self type of the element. Needed for static type checking. * @param I self type of the element. Needed for static type checking.
* @param R the type of space. * @param R the type of space.
*/ */
interface RingElement<T, I : RingElement<T, I, R>, R : Ring<T>> : SpaceElement<T, I, R> { public interface RingElement<T, I : RingElement<T, I, R>, R : Ring<T>> : SpaceElement<T, I, R> {
/** /**
* Multiplies this element by another one. * Multiplies this element by another one.
* *
* @param b the multiplicand. * @param b the multiplicand.
* @return the product. * @return the product.
*/ */
operator fun times(b: T): I = context.multiply(unwrap(), b).wrap() public operator fun times(b: T): I = context.multiply(unwrap(), b).wrap()
} }
/** /**
@ -95,7 +95,7 @@ interface RingElement<T, I : RingElement<T, I, R>, R : Ring<T>> : SpaceElement<T
* @param I self type of the element. Needed for static type checking. * @param I self type of the element. Needed for static type checking.
* @param F the type of field. * @param F the type of field.
*/ */
interface FieldElement<T, I : FieldElement<T, I, F>, F : Field<T>> : RingElement<T, I, F> { public interface FieldElement<T, I : FieldElement<T, I, F>, F : Field<T>> : RingElement<T, I, F> {
override val context: F override val context: F
/** /**
@ -104,5 +104,5 @@ interface FieldElement<T, I : FieldElement<T, I, F>, F : Field<T>> : RingElement
* @param b the divisor. * @param b the divisor.
* @return the quotient. * @return the quotient.
*/ */
operator fun div(b: T): I = context.divide(unwrap(), b).wrap() public operator fun div(b: T): I = context.divide(unwrap(), b).wrap()
} }

View File

@ -7,7 +7,7 @@ package scientifik.kmath.operations
* @param data the iterable to sum up. * @param data the iterable to sum up.
* @return the sum. * @return the sum.
*/ */
fun <T> Space<T>.sum(data: Iterable<T>): T = data.fold(zero) { left, right -> add(left, right) } public fun <T> Space<T>.sum(data: Iterable<T>): T = data.fold(zero) { left, right -> add(left, right) }
/** /**
* Returns the sum of all elements in the sequence in this [Space]. * Returns the sum of all elements in the sequence in this [Space].
@ -16,7 +16,7 @@ fun <T> Space<T>.sum(data: Iterable<T>): T = data.fold(zero) { left, right -> ad
* @param data the sequence to sum up. * @param data the sequence to sum up.
* @return the sum. * @return the sum.
*/ */
fun <T> Space<T>.sum(data: Sequence<T>): T = data.fold(zero) { left, right -> add(left, right) } public fun <T> Space<T>.sum(data: Sequence<T>): T = data.fold(zero) { left, right -> add(left, right) }
/** /**
* Returns an average value of elements in the iterable in this [Space]. * Returns an average value of elements in the iterable in this [Space].
@ -25,7 +25,7 @@ fun <T> Space<T>.sum(data: Sequence<T>): T = data.fold(zero) { left, right -> ad
* @param data the iterable to find average. * @param data the iterable to find average.
* @return the average value. * @return the average value.
*/ */
fun <T> Space<T>.average(data: Iterable<T>): T = sum(data) / data.count() public fun <T> Space<T>.average(data: Iterable<T>): T = sum(data) / data.count()
/** /**
* Returns an average value of elements in the sequence in this [Space]. * Returns an average value of elements in the sequence in this [Space].
@ -34,7 +34,7 @@ fun <T> Space<T>.average(data: Iterable<T>): T = sum(data) / data.count()
* @param data the sequence to find average. * @param data the sequence to find average.
* @return the average value. * @return the average value.
*/ */
fun <T> Space<T>.average(data: Sequence<T>): T = sum(data) / data.count() public fun <T> Space<T>.average(data: Sequence<T>): T = sum(data) / data.count()
/** /**
* Returns the sum of all elements in the iterable in provided space. * Returns the sum of all elements in the iterable in provided space.
@ -43,7 +43,7 @@ fun <T> Space<T>.average(data: Sequence<T>): T = sum(data) / data.count()
* @param space the algebra that provides addition. * @param space the algebra that provides addition.
* @return the sum. * @return the sum.
*/ */
fun <T> Iterable<T>.sumWith(space: Space<T>): T = space.sum(this) public fun <T> Iterable<T>.sumWith(space: Space<T>): T = space.sum(this)
/** /**
* Returns the sum of all elements in the sequence in provided space. * Returns the sum of all elements in the sequence in provided space.
@ -52,7 +52,7 @@ fun <T> Iterable<T>.sumWith(space: Space<T>): T = space.sum(this)
* @param space the algebra that provides addition. * @param space the algebra that provides addition.
* @return the sum. * @return the sum.
*/ */
fun <T> Sequence<T>.sumWith(space: Space<T>): T = space.sum(this) public fun <T> Sequence<T>.sumWith(space: Space<T>): T = space.sum(this)
/** /**
* Returns an average value of elements in the iterable in this [Space]. * Returns an average value of elements in the iterable in this [Space].
@ -61,7 +61,7 @@ fun <T> Sequence<T>.sumWith(space: Space<T>): T = space.sum(this)
* @param space the algebra that provides addition and division. * @param space the algebra that provides addition and division.
* @return the average value. * @return the average value.
*/ */
fun <T> Iterable<T>.averageWith(space: Space<T>): T = space.average(this) public fun <T> Iterable<T>.averageWith(space: Space<T>): T = space.average(this)
/** /**
* Returns an average value of elements in the sequence in this [Space]. * Returns an average value of elements in the sequence in this [Space].
@ -70,7 +70,7 @@ fun <T> Iterable<T>.averageWith(space: Space<T>): T = space.average(this)
* @param space the algebra that provides addition and division. * @param space the algebra that provides addition and division.
* @return the average value. * @return the average value.
*/ */
fun <T> Sequence<T>.averageWith(space: Space<T>): T = space.average(this) public fun <T> Sequence<T>.averageWith(space: Space<T>): T = space.average(this)
//TODO optimized power operation //TODO optimized power operation
@ -82,7 +82,7 @@ fun <T> Sequence<T>.averageWith(space: Space<T>): T = space.average(this)
* @param power the exponent. * @param power the exponent.
* @return the base raised to the power. * @return the base raised to the power.
*/ */
fun <T> Ring<T>.power(arg: T, power: Int): T { public fun <T> Ring<T>.power(arg: T, power: Int): T {
require(power >= 0) { "The power can't be negative." } require(power >= 0) { "The power can't be negative." }
require(power != 0 || arg != zero) { "The $zero raised to $power is not defined." } require(power != 0 || arg != zero) { "The $zero raised to $power is not defined." }
if (power == 0) return one if (power == 0) return one
@ -99,7 +99,7 @@ fun <T> Ring<T>.power(arg: T, power: Int): T {
* @param power the exponent. * @param power the exponent.
* @return the base raised to the power. * @return the base raised to the power.
*/ */
fun <T> Field<T>.power(arg: T, power: Int): T { public fun <T> Field<T>.power(arg: T, power: Int): T {
require(power != 0 || arg != zero) { "The $zero raised to $power is not defined." } require(power != 0 || arg != zero) { "The $zero raised to $power is not defined." }
if (power == 0) return one if (power == 0) return one
if (power < 0) return one / (this as Ring<T>).power(arg, -power) if (power < 0) return one / (this as Ring<T>).power(arg, -power)

View File

@ -3,22 +3,21 @@ package scientifik.kmath.operations
import scientifik.kmath.operations.BigInt.Companion.BASE import scientifik.kmath.operations.BigInt.Companion.BASE
import scientifik.kmath.operations.BigInt.Companion.BASE_SIZE import scientifik.kmath.operations.BigInt.Companion.BASE_SIZE
import scientifik.kmath.structures.* import scientifik.kmath.structures.*
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.math.log2 import kotlin.math.log2
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import kotlin.math.sign import kotlin.math.sign
typealias Magnitude = UIntArray public typealias Magnitude = UIntArray
typealias TBase = ULong public typealias TBase = ULong
/** /**
* Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger). * Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger).
* *
* @author Robert Drynkin (https://github.com/robdrynkin) and Peter Klimai (https://github.com/pklimai) * @author Robert Drynkin (https://github.com/robdrynkin) and Peter Klimai (https://github.com/pklimai)
*/ */
object BigIntField : Field<BigInt> { public object BigIntField : Field<BigInt> {
override val zero: BigInt = BigInt.ZERO override val zero: BigInt = BigInt.ZERO
override val one: BigInt = BigInt.ONE override val one: BigInt = BigInt.ONE
@ -29,113 +28,93 @@ object BigIntField : Field<BigInt> {
override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b) override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b)
operator fun String.unaryPlus(): BigInt = this.parseBigInteger() ?: error("Can't parse $this as big integer") public operator fun String.unaryPlus(): BigInt = this.parseBigInteger() ?: error("Can't parse $this as big integer")
operator fun String.unaryMinus(): BigInt = public operator fun String.unaryMinus(): BigInt =
-(this.parseBigInteger() ?: error("Can't parse $this as big integer")) -(this.parseBigInteger() ?: error("Can't parse $this as big integer"))
override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b) override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b)
} }
class BigInt internal constructor( public class BigInt internal constructor(
private val sign: Byte, private val sign: Byte,
private val magnitude: Magnitude private val magnitude: Magnitude
) : Comparable<BigInt> { ) : Comparable<BigInt> {
override fun compareTo(other: BigInt): Int { override fun compareTo(other: BigInt): Int = when {
return when {
(this.sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0 (this.sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0
this.sign < other.sign -> -1 this.sign < other.sign -> -1
this.sign > other.sign -> 1 this.sign > other.sign -> 1
else -> this.sign * compareMagnitudes(this.magnitude, other.magnitude) else -> this.sign * compareMagnitudes(this.magnitude, other.magnitude)
} }
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean =
if (other is BigInt) { if (other is BigInt) compareTo(other) == 0 else error("Can't compare KBigInteger to a different type")
return this.compareTo(other) == 0
} else error("Can't compare KBigInteger to a different type")
}
override fun hashCode(): Int { override fun hashCode(): Int = magnitude.hashCode() + sign
return magnitude.hashCode() + this.sign
}
fun abs(): BigInt = if (sign == 0.toByte()) this else BigInt(1, magnitude) public fun abs(): BigInt = if (sign == 0.toByte()) this else BigInt(1, magnitude)
operator fun unaryMinus(): BigInt { public operator fun unaryMinus(): BigInt =
return if (this.sign == 0.toByte()) this else BigInt((-this.sign).toByte(), this.magnitude) if (this.sign == 0.toByte()) this else BigInt((-this.sign).toByte(), this.magnitude)
}
operator fun plus(b: BigInt): BigInt { public operator fun plus(b: BigInt): BigInt = when {
return when {
b.sign == 0.toByte() -> this b.sign == 0.toByte() -> this
this.sign == 0.toByte() -> b sign == 0.toByte() -> b
this == -b -> ZERO this == -b -> ZERO
this.sign == b.sign -> BigInt(this.sign, addMagnitudes(this.magnitude, b.magnitude)) sign == b.sign -> BigInt(sign, addMagnitudes(magnitude, b.magnitude))
else -> { else -> {
val comp: Int = compareMagnitudes(this.magnitude, b.magnitude) val comp = compareMagnitudes(magnitude, b.magnitude)
if (comp == 1) { if (comp == 1)
BigInt(this.sign, subtractMagnitudes(this.magnitude, b.magnitude)) BigInt(sign, subtractMagnitudes(magnitude, b.magnitude))
} else { else
BigInt((-this.sign).toByte(), subtractMagnitudes(b.magnitude, this.magnitude)) BigInt((-sign).toByte(), subtractMagnitudes(b.magnitude, magnitude))
}
}
} }
} }
operator fun minus(b: BigInt): BigInt { public operator fun minus(b: BigInt): BigInt = this + (-b)
return this + (-b)
}
operator fun times(b: BigInt): BigInt { public operator fun times(b: BigInt): BigInt = when {
return when {
this.sign == 0.toByte() -> ZERO this.sign == 0.toByte() -> ZERO
b.sign == 0.toByte() -> ZERO b.sign == 0.toByte() -> ZERO
// TODO: Karatsuba // TODO: Karatsuba
else -> BigInt((this.sign * b.sign).toByte(), multiplyMagnitudes(this.magnitude, b.magnitude)) else -> BigInt((this.sign * b.sign).toByte(), multiplyMagnitudes(this.magnitude, b.magnitude))
} }
}
operator fun times(other: UInt): BigInt { public operator fun times(other: UInt): BigInt = when {
return when { sign == 0.toByte() -> ZERO
this.sign == 0.toByte() -> ZERO
other == 0U -> ZERO other == 0U -> ZERO
else -> BigInt(this.sign, multiplyMagnitudeByUInt(this.magnitude, other)) else -> BigInt(sign, multiplyMagnitudeByUInt(magnitude, other))
}
} }
operator fun times(other: Int): BigInt { public operator fun times(other: Int): BigInt = if (other > 0)
return if (other > 0)
this * kotlin.math.abs(other).toUInt() this * kotlin.math.abs(other).toUInt()
else else
-this * kotlin.math.abs(other).toUInt() -this * kotlin.math.abs(other).toUInt()
}
operator fun div(other: UInt): BigInt { public operator fun div(other: UInt): BigInt = BigInt(this.sign, divideMagnitudeByUInt(this.magnitude, other))
return BigInt(this.sign, divideMagnitudeByUInt(this.magnitude, other))
}
operator fun div(other: Int): BigInt { public operator fun div(other: Int): BigInt = BigInt(
return BigInt(
(this.sign * other.sign).toByte(), (this.sign * other.sign).toByte(),
divideMagnitudeByUInt(this.magnitude, kotlin.math.abs(other).toUInt()) divideMagnitudeByUInt(this.magnitude, kotlin.math.abs(other).toUInt())
) )
}
private fun division(other: BigInt): Pair<BigInt, BigInt> { private fun division(other: BigInt): Pair<BigInt, BigInt> {
// Long division algorithm: // Long division algorithm:
// https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_(unsigned)_with_remainder // https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_(unsigned)_with_remainder
// TODO: Implement more effective algorithm // TODO: Implement more effective algorithm
var q: BigInt = ZERO var q = ZERO
var r: BigInt = ZERO var r = ZERO
val bitSize = val bitSize =
(BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: 0f + 1)).toInt() (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: 0f + 1)).toInt()
for (i in bitSize downTo 0) { for (i in bitSize downTo 0) {
r = r shl 1 r = r shl 1
r = r or ((abs(this) shr i) and ONE) r = r or ((abs(this) shr i) and ONE)
if (r >= abs(other)) { if (r >= abs(other)) {
r -= abs(other) r -= abs(other)
q += (ONE shl i) q += (ONE shl i)
@ -145,101 +124,86 @@ class BigInt internal constructor(
return Pair(BigInt((this.sign * other.sign).toByte(), q.magnitude), r) return Pair(BigInt((this.sign * other.sign).toByte(), q.magnitude), r)
} }
operator fun div(other: BigInt): BigInt { public operator fun div(other: BigInt): BigInt = this.division(other).first
return this.division(other).first
}
infix fun shl(i: Int): BigInt { public infix fun shl(i: Int): BigInt {
if (this == ZERO) return ZERO if (this == ZERO) return ZERO
if (i == 0) return this if (i == 0) return this
val fullShifts = i / BASE_SIZE + 1 val fullShifts = i / BASE_SIZE + 1
val relShift = i % BASE_SIZE val relShift = i % BASE_SIZE
val shiftLeft = { x: UInt -> if (relShift >= 32) 0U else x shl relShift } val shiftLeft = { x: UInt -> if (relShift >= 32) 0U else x shl relShift }
val shiftRight = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shr (BASE_SIZE - relShift) } val shiftRight = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shr (BASE_SIZE - relShift) }
val newMagnitude = Magnitude(this.magnitude.size + fullShifts)
val newMagnitude: Magnitude = Magnitude(this.magnitude.size + fullShifts)
for (j in this.magnitude.indices) { for (j in this.magnitude.indices) {
newMagnitude[j + fullShifts - 1] = shiftLeft(this.magnitude[j]) newMagnitude[j + fullShifts - 1] = shiftLeft(this.magnitude[j])
if (j != 0) {
if (j != 0)
newMagnitude[j + fullShifts - 1] = newMagnitude[j + fullShifts - 1] or shiftRight(this.magnitude[j - 1]) newMagnitude[j + fullShifts - 1] = newMagnitude[j + fullShifts - 1] or shiftRight(this.magnitude[j - 1])
} }
}
newMagnitude[this.magnitude.size + fullShifts - 1] = shiftRight(this.magnitude.last()) newMagnitude[this.magnitude.size + fullShifts - 1] = shiftRight(this.magnitude.last())
return BigInt(this.sign, stripLeadingZeros(newMagnitude)) return BigInt(this.sign, stripLeadingZeros(newMagnitude))
} }
infix fun shr(i: Int): BigInt { public infix fun shr(i: Int): BigInt {
if (this == ZERO) return ZERO if (this == ZERO) return ZERO
if (i == 0) return this if (i == 0) return this
val fullShifts = i / BASE_SIZE val fullShifts = i / BASE_SIZE
val relShift = i % BASE_SIZE val relShift = i % BASE_SIZE
val shiftRight = { x: UInt -> if (relShift >= 32) 0U else x shr relShift } val shiftRight = { x: UInt -> if (relShift >= 32) 0U else x shr relShift }
val shiftLeft = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shl (BASE_SIZE - relShift) } val shiftLeft = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shl (BASE_SIZE - relShift) }
if (this.magnitude.size - fullShifts <= 0) { if (this.magnitude.size - fullShifts <= 0) return ZERO
return ZERO
}
val newMagnitude: Magnitude = Magnitude(this.magnitude.size - fullShifts) val newMagnitude: Magnitude = Magnitude(this.magnitude.size - fullShifts)
for (j in fullShifts until this.magnitude.size) { for (j in fullShifts until this.magnitude.size) {
newMagnitude[j - fullShifts] = shiftRight(this.magnitude[j]) newMagnitude[j - fullShifts] = shiftRight(this.magnitude[j])
if (j != this.magnitude.size - 1) {
if (j != this.magnitude.size - 1)
newMagnitude[j - fullShifts] = newMagnitude[j - fullShifts] or shiftLeft(this.magnitude[j + 1]) newMagnitude[j - fullShifts] = newMagnitude[j - fullShifts] or shiftLeft(this.magnitude[j + 1])
} }
}
return BigInt(this.sign, stripLeadingZeros(newMagnitude)) return BigInt(this.sign, stripLeadingZeros(newMagnitude))
} }
infix fun or(other: BigInt): BigInt { public infix fun or(other: BigInt): BigInt {
if (this == ZERO) return other if (this == ZERO) return other
if (other == ZERO) return this if (other == ZERO) return this
val resSize = max(this.magnitude.size, other.magnitude.size) val resSize = max(this.magnitude.size, other.magnitude.size)
val newMagnitude: Magnitude = Magnitude(resSize) val newMagnitude: Magnitude = Magnitude(resSize)
for (i in 0 until resSize) { for (i in 0 until resSize) {
if (i < this.magnitude.size) { if (i < this.magnitude.size) newMagnitude[i] = newMagnitude[i] or this.magnitude[i]
newMagnitude[i] = newMagnitude[i] or this.magnitude[i] if (i < other.magnitude.size) newMagnitude[i] = newMagnitude[i] or other.magnitude[i]
}
if (i < other.magnitude.size) {
newMagnitude[i] = newMagnitude[i] or other.magnitude[i]
}
} }
return BigInt(1, stripLeadingZeros(newMagnitude)) return BigInt(1, stripLeadingZeros(newMagnitude))
} }
infix fun and(other: BigInt): BigInt { public infix fun and(other: BigInt): BigInt {
if ((this == ZERO) or (other == ZERO)) return ZERO if ((this == ZERO) or (other == ZERO)) return ZERO
val resSize = min(this.magnitude.size, other.magnitude.size) val resSize = min(this.magnitude.size, other.magnitude.size)
val newMagnitude: Magnitude = Magnitude(resSize) val newMagnitude: Magnitude = Magnitude(resSize)
for (i in 0 until resSize) { for (i in 0 until resSize) newMagnitude[i] = this.magnitude[i] and other.magnitude[i]
newMagnitude[i] = this.magnitude[i] and other.magnitude[i]
}
return BigInt(1, stripLeadingZeros(newMagnitude)) return BigInt(1, stripLeadingZeros(newMagnitude))
} }
operator fun rem(other: Int): Int { public operator fun rem(other: Int): Int {
val res = this - (this / other) * other val res = this - (this / other) * other
return if (res == ZERO) 0 else res.sign * res.magnitude[0].toInt() return if (res == ZERO) 0 else res.sign * res.magnitude[0].toInt()
} }
operator fun rem(other: BigInt): BigInt { public operator fun rem(other: BigInt): BigInt = this - (this / other) * other
return this - (this / other) * other
}
fun modPow(exponent: BigInt, m: BigInt): BigInt { public fun modPow(exponent: BigInt, m: BigInt): BigInt = when {
return when {
exponent == ZERO -> ONE exponent == ZERO -> ONE
exponent % 2 == 1 -> (this * modPow(exponent - ONE, m)) % m exponent % 2 == 1 -> (this * modPow(exponent - ONE, m)) % m
else -> { else -> {
val sqRoot = modPow(exponent / 2, m) val sqRoot = modPow(exponent / 2, m)
(sqRoot * sqRoot) % m (sqRoot * sqRoot) % m
} }
} }
}
override fun toString(): String { override fun toString(): String {
if (this.sign == 0.toByte()) { if (this.sign == 0.toByte()) {
@ -261,11 +225,11 @@ class BigInt internal constructor(
return res return res
} }
companion object { public companion object {
const val BASE: ULong = 0xffffffffUL public const val BASE: ULong = 0xffffffffUL
const val BASE_SIZE: Int = 32 public const val BASE_SIZE: Int = 32
val ZERO: BigInt = BigInt(0, uintArrayOf()) public val ZERO: BigInt = BigInt(0, uintArrayOf())
val ONE: BigInt = BigInt(1, uintArrayOf(1u)) public val ONE: BigInt = BigInt(1, uintArrayOf(1u))
private val hexMapping: HashMap<UInt, String> = hashMapOf( private val hexMapping: HashMap<UInt, String> = hashMapOf(
0U to "0", 1U to "1", 2U to "2", 3U to "3", 0U to "0", 1U to "1", 2U to "2", 3U to "3",
@ -349,11 +313,13 @@ class BigInt internal constructor(
for (i in mag1.indices) { for (i in mag1.indices) {
var carry: ULong = 0UL var carry: ULong = 0UL
for (j in mag2.indices) { for (j in mag2.indices) {
val cur: ULong = result[i + j].toULong() + mag1[i].toULong() * mag2[j].toULong() + carry val cur: ULong = result[i + j].toULong() + mag1[i].toULong() * mag2[j].toULong() + carry
result[i + j] = (cur and BASE.toULong()).toUInt() result[i + j] = (cur and BASE.toULong()).toUInt()
carry = cur shr BASE_SIZE carry = cur shr BASE_SIZE
} }
result[i + mag2.size] = (carry and BASE).toUInt() result[i + mag2.size] = (carry and BASE).toUInt()
} }
@ -361,15 +327,16 @@ class BigInt internal constructor(
} }
private fun divideMagnitudeByUInt(mag: Magnitude, x: UInt): Magnitude { private fun divideMagnitudeByUInt(mag: Magnitude, x: UInt): Magnitude {
val resultLength: Int = mag.size val resultLength = mag.size
val result = Magnitude(resultLength) val result = Magnitude(resultLength)
var carry: ULong = 0UL var carry = 0uL
for (i in mag.size - 1 downTo 0) { for (i in mag.size - 1 downTo 0) {
val cur: ULong = mag[i].toULong() + (carry shl BASE_SIZE) val cur: ULong = mag[i].toULong() + (carry shl BASE_SIZE)
result[i] = (cur / x).toUInt() result[i] = (cur / x).toUInt()
carry = cur % x carry = cur % x
} }
return stripLeadingZeros(result) return stripLeadingZeros(result)
} }
@ -377,31 +344,29 @@ class BigInt internal constructor(
} }
private fun stripLeadingZeros(mag: Magnitude): Magnitude { private fun stripLeadingZeros(mag: Magnitude): Magnitude {
if (mag.isEmpty() || mag.last() != 0U) { if (mag.isEmpty() || mag.last() != 0U) return mag
return mag var resSize = mag.size - 1
}
var resSize: Int = mag.size - 1
while (mag[resSize] == 0U) { while (mag[resSize] == 0U) {
if (resSize == 0) if (resSize == 0) break
break
resSize -= 1 resSize -= 1
} }
return mag.sliceArray(IntRange(0, resSize)) return mag.sliceArray(IntRange(0, resSize))
} }
fun abs(x: BigInt): BigInt = x.abs() public fun abs(x: BigInt): BigInt = x.abs()
/** /**
* Convert this [Int] to [BigInt] * Convert this [Int] to [BigInt]
*/ */
fun Int.toBigInt(): BigInt = BigInt(sign.toByte(), uintArrayOf(kotlin.math.abs(this).toUInt())) public fun Int.toBigInt(): BigInt = BigInt(sign.toByte(), uintArrayOf(kotlin.math.abs(this).toUInt()))
/** /**
* Convert this [Long] to [BigInt] * Convert this [Long] to [BigInt]
*/ */
fun Long.toBigInt(): BigInt = BigInt( public fun Long.toBigInt(): BigInt = BigInt(
sign.toByte(), stripLeadingZeros( sign.toByte(), stripLeadingZeros(
uintArrayOf( uintArrayOf(
(kotlin.math.abs(this).toULong() and BASE).toUInt(), (kotlin.math.abs(this).toULong() and BASE).toUInt(),
@ -413,13 +378,14 @@ fun Long.toBigInt(): BigInt = BigInt(
/** /**
* Convert UInt to [BigInt] * Convert UInt to [BigInt]
*/ */
fun UInt.toBigInt(): BigInt = BigInt(1, uintArrayOf(this)) public fun UInt.toBigInt(): BigInt = BigInt(1, uintArrayOf(this))
/** /**
* Convert ULong to [BigInt] * Convert ULong to [BigInt]
*/ */
fun ULong.toBigInt(): BigInt = BigInt( public fun ULong.toBigInt(): BigInt = BigInt(
1, 1,
stripLeadingZeros( stripLeadingZeros(
uintArrayOf( uintArrayOf(
(this and BASE).toUInt(), (this and BASE).toUInt(),
@ -431,12 +397,12 @@ fun ULong.toBigInt(): BigInt = BigInt(
/** /**
* Create a [BigInt] with this array of magnitudes with protective copy * Create a [BigInt] with this array of magnitudes with protective copy
*/ */
fun UIntArray.toBigInt(sign: Byte): BigInt { public fun UIntArray.toBigInt(sign: Byte): BigInt {
require(sign != 0.toByte() || !isNotEmpty()) require(sign != 0.toByte() || !isNotEmpty())
return BigInt(sign, copyOf()) return BigInt(sign, copyOf())
} }
val hexChToInt: MutableMap<Char, Int> = hashMapOf( private val hexChToInt: MutableMap<Char, Int> = hashMapOf(
'0' to 0, '1' to 1, '2' to 2, '3' to 3, '0' to 0, '1' to 1, '2' to 2, '3' to 3,
'4' to 4, '5' to 5, '6' to 6, '7' to 7, '4' to 4, '5' to 5, '6' to 6, '7' to 7,
'8' to 8, '9' to 9, 'A' to 10, 'B' to 11, '8' to 8, '9' to 9, 'A' to 10, 'B' to 11,
@ -446,9 +412,10 @@ val hexChToInt: MutableMap<Char, Int> = hashMapOf(
/** /**
* Returns null if a valid number can not be read from a string * Returns null if a valid number can not be read from a string
*/ */
fun String.parseBigInteger(): BigInt? { public fun String.parseBigInteger(): BigInt? {
val sign: Int val sign: Int
val sPositive: String val sPositive: String
when { when {
this[0] == '+' -> { this[0] == '+' -> {
sign = +1 sign = +1
@ -463,18 +430,21 @@ fun String.parseBigInteger(): BigInt? {
sign = +1 sign = +1
} }
} }
var res = BigInt.ZERO var res = BigInt.ZERO
var digitValue = BigInt.ONE var digitValue = BigInt.ONE
val sPositiveUpper = sPositive.toUpperCase() val sPositiveUpper = sPositive.toUpperCase()
if (sPositiveUpper.startsWith("0X")) { // hex representation if (sPositiveUpper.startsWith("0X")) { // hex representation
val sHex = sPositiveUpper.substring(2) val sHex = sPositiveUpper.substring(2)
for (ch in sHex.reversed()) { for (ch in sHex.reversed()) {
if (ch == '_') continue if (ch == '_') continue
res += digitValue * (hexChToInt[ch] ?: return null) res += digitValue * (hexChToInt[ch] ?: return null)
digitValue *= 16.toBigInt() digitValue *= 16.toBigInt()
} }
} else { // decimal representation } else for (ch in sPositiveUpper.reversed()) {
for (ch in sPositiveUpper.reversed()) { // decimal representation
if (ch == '_') continue if (ch == '_') continue
if (ch !in '0'..'9') { if (ch !in '0'..'9') {
return null return null
@ -482,24 +452,24 @@ fun String.parseBigInteger(): BigInt? {
res += digitValue * (ch.toInt() - '0'.toInt()) res += digitValue * (ch.toInt() - '0'.toInt())
digitValue *= 10.toBigInt() digitValue *= 10.toBigInt()
} }
}
return res * sign return res * sign
} }
inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> { public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> {
contract { callsInPlace(initializer) } contract { callsInPlace(initializer) }
return boxing(size, initializer) return boxing(size, initializer)
} }
inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer<BigInt> { public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer<BigInt> {
contract { callsInPlace(initializer) } contract { callsInPlace(initializer) }
return boxing(size, initializer) return boxing(size, initializer)
} }
fun NDAlgebra.Companion.bigInt(vararg shape: Int): BoxingNDRing<BigInt, BigIntField> = public fun NDAlgebra.Companion.bigInt(vararg shape: Int): BoxingNDRing<BigInt, BigIntField> =
BoxingNDRing(shape, BigIntField, Buffer.Companion::bigInt) BoxingNDRing(shape, BigIntField, Buffer.Companion::bigInt)
fun NDElement.Companion.bigInt( public fun NDElement.Companion.bigInt(
vararg shape: Int, vararg shape: Int,
initializer: BigIntField.(IntArray) -> BigInt initializer: BigIntField.(IntArray) -> BigInt
): BufferedNDRingElement<BigInt, BigIntField> = NDAlgebra.bigInt(*shape).produce(initializer) ): BufferedNDRingElement<BigInt, BigIntField> = NDAlgebra.bigInt(*shape).produce(initializer)

View File

@ -6,20 +6,19 @@ import scientifik.kmath.structures.MutableBuffer
import scientifik.memory.MemoryReader import scientifik.memory.MemoryReader
import scientifik.memory.MemorySpec import scientifik.memory.MemorySpec
import scientifik.memory.MemoryWriter import scientifik.memory.MemoryWriter
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.math.* import kotlin.math.*
/** /**
* This complex's conjugate. * This complex's conjugate.
*/ */
val Complex.conjugate: Complex public val Complex.conjugate: Complex
get() = Complex(re, -im) get() = Complex(re, -im)
/** /**
* This complex's reciprocal. * This complex's reciprocal.
*/ */
val Complex.reciprocal: Complex public val Complex.reciprocal: Complex
get() { get() {
val scale = re * re + im * im val scale = re * re + im * im
return Complex(re / scale, -im / scale) return Complex(re / scale, -im / scale)
@ -28,13 +27,13 @@ val Complex.reciprocal: Complex
/** /**
* Absolute value of complex number. * Absolute value of complex number.
*/ */
val Complex.r: Double public val Complex.r: Double
get() = sqrt(re * re + im * im) get() = sqrt(re * re + im * im)
/** /**
* An angle between vector represented by complex number and X axis. * An angle between vector represented by complex number and X axis.
*/ */
val Complex.theta: Double public val Complex.theta: Double
get() = atan(im / re) get() = atan(im / re)
private val PI_DIV_2 = Complex(PI / 2, 0) private val PI_DIV_2 = Complex(PI / 2, 0)
@ -42,14 +41,14 @@ private val PI_DIV_2 = Complex(PI / 2, 0)
/** /**
* A field of [Complex]. * A field of [Complex].
*/ */
object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex> { public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex> {
override val zero: Complex = 0.0.toComplex() override val zero: Complex = 0.0.toComplex()
override val one: Complex = 1.0.toComplex() override val one: Complex = 1.0.toComplex()
/** /**
* The imaginary unit. * The imaginary unit.
*/ */
val i: Complex = Complex(0.0, 1.0) public val i: Complex = Complex(0.0, 1.0)
override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im) override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im)
@ -117,7 +116,7 @@ object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex> {
* @param c the augend. * @param c the augend.
* @return the sum. * @return the sum.
*/ */
operator fun Double.plus(c: Complex): Complex = add(this.toComplex(), c) public operator fun Double.plus(c: Complex): Complex = add(this.toComplex(), c)
/** /**
* Subtracts complex number from real one. * Subtracts complex number from real one.
@ -126,7 +125,7 @@ object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex> {
* @param c the subtrahend. * @param c the subtrahend.
* @return the difference. * @return the difference.
*/ */
operator fun Double.minus(c: Complex): Complex = add(this.toComplex(), -c) public operator fun Double.minus(c: Complex): Complex = add(this.toComplex(), -c)
/** /**
* Adds real number to complex one. * Adds real number to complex one.
@ -135,7 +134,7 @@ object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex> {
* @param d the augend. * @param d the augend.
* @return the sum. * @return the sum.
*/ */
operator fun Complex.plus(d: Double): Complex = d + this public operator fun Complex.plus(d: Double): Complex = d + this
/** /**
* Subtracts real number from complex one. * Subtracts real number from complex one.
@ -144,7 +143,7 @@ object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex> {
* @param d the subtrahend. * @param d the subtrahend.
* @return the difference. * @return the difference.
*/ */
operator fun Complex.minus(d: Double): Complex = add(this, -d.toComplex()) public operator fun Complex.minus(d: Double): Complex = add(this, -d.toComplex())
/** /**
* Multiplies real number by complex one. * Multiplies real number by complex one.
@ -153,7 +152,7 @@ object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex> {
* @param c the multiplicand. * @param c the multiplicand.
* @receiver the product. * @receiver the product.
*/ */
operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this) public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this)
override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
@ -166,8 +165,8 @@ object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex> {
* @property re The real part. * @property re The real part.
* @property im The imaginary part. * @property im The imaginary part.
*/ */
data class Complex(val re: Double, val im: Double) : FieldElement<Complex, Complex, ComplexField>, Comparable<Complex> { public data class Complex(val re: Double, val im: Double) : FieldElement<Complex, Complex, ComplexField>, Comparable<Complex> {
constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble()) public constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble())
override val context: ComplexField get() = ComplexField override val context: ComplexField get() = ComplexField
@ -177,7 +176,7 @@ data class Complex(val re: Double, val im: Double) : FieldElement<Complex, Compl
override fun compareTo(other: Complex): Int = r.compareTo(other.r) override fun compareTo(other: Complex): Int = r.compareTo(other.r)
companion object : MemorySpec<Complex> { public companion object : MemorySpec<Complex> {
override val objectSize: Int = 16 override val objectSize: Int = 16
override fun MemoryReader.read(offset: Int): Complex = override fun MemoryReader.read(offset: Int): Complex =
@ -196,14 +195,14 @@ data class Complex(val re: Double, val im: Double) : FieldElement<Complex, Compl
* @receiver the real part. * @receiver the real part.
* @return the new complex number. * @return the new complex number.
*/ */
fun Number.toComplex(): Complex = Complex(this, 0.0) public fun Number.toComplex(): Complex = Complex(this, 0.0)
inline fun Buffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer<Complex> { public inline fun Buffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer<Complex> {
contract { callsInPlace(init) } contract { callsInPlace(init) }
return MemoryBuffer.create(Complex, size, init) return MemoryBuffer.create(Complex, size, init)
} }
inline fun MutableBuffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer<Complex> { public inline fun MutableBuffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer<Complex> {
contract { callsInPlace(init) } contract { callsInPlace(init) }
return MemoryBuffer.create(Complex, size, init) return MemoryBuffer.create(Complex, size, init)
} }

View File

@ -7,7 +7,7 @@ import kotlin.math.pow as kpow
/** /**
* Advanced Number-like semifield that implements basic operations. * Advanced Number-like semifield that implements basic operations.
*/ */
interface ExtendedFieldOperations<T> : public interface ExtendedFieldOperations<T> :
FieldOperations<T>, FieldOperations<T>,
TrigonometricOperations<T>, TrigonometricOperations<T>,
HyperbolicOperations<T>, HyperbolicOperations<T>,
@ -41,7 +41,7 @@ interface ExtendedFieldOperations<T> :
/** /**
* Advanced Number-like field that implements basic operations. * Advanced Number-like field that implements basic operations.
*/ */
interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T> { public interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T> {
override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2 override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2
override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2 override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2
override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg))

View File

@ -5,230 +5,230 @@ package scientifik.kmath.operations
* *
* @param T the type of element of this structure. * @param T the type of element of this structure.
*/ */
interface TrigonometricOperations<T> : Algebra<T> { public interface TrigonometricOperations<T> : Algebra<T> {
/** /**
* Computes the sine of [arg]. * Computes the sine of [arg].
*/ */
fun sin(arg: T): T public fun sin(arg: T): T
/** /**
* Computes the cosine of [arg]. * Computes the cosine of [arg].
*/ */
fun cos(arg: T): T public fun cos(arg: T): T
/** /**
* Computes the tangent of [arg]. * Computes the tangent of [arg].
*/ */
fun tan(arg: T): T public fun tan(arg: T): T
/** /**
* Computes the inverse sine of [arg]. * Computes the inverse sine of [arg].
*/ */
fun asin(arg: T): T public fun asin(arg: T): T
/** /**
* Computes the inverse cosine of [arg]. * Computes the inverse cosine of [arg].
*/ */
fun acos(arg: T): T public fun acos(arg: T): T
/** /**
* Computes the inverse tangent of [arg]. * Computes the inverse tangent of [arg].
*/ */
fun atan(arg: T): T public fun atan(arg: T): T
companion object { public companion object {
/** /**
* The identifier of sine. * The identifier of sine.
*/ */
const val SIN_OPERATION: String = "sin" public const val SIN_OPERATION: String = "sin"
/** /**
* The identifier of cosine. * The identifier of cosine.
*/ */
const val COS_OPERATION: String = "cos" public const val COS_OPERATION: String = "cos"
/** /**
* The identifier of tangent. * The identifier of tangent.
*/ */
const val TAN_OPERATION: String = "tan" public const val TAN_OPERATION: String = "tan"
/** /**
* The identifier of inverse sine. * The identifier of inverse sine.
*/ */
const val ASIN_OPERATION: String = "asin" public const val ASIN_OPERATION: String = "asin"
/** /**
* The identifier of inverse cosine. * The identifier of inverse cosine.
*/ */
const val ACOS_OPERATION: String = "acos" public const val ACOS_OPERATION: String = "acos"
/** /**
* The identifier of inverse tangent. * The identifier of inverse tangent.
*/ */
const val ATAN_OPERATION: String = "atan" public const val ATAN_OPERATION: String = "atan"
} }
} }
/** /**
* Computes the sine of [arg]. * Computes the sine of [arg].
*/ */
fun <T : MathElement<out TrigonometricOperations<T>>> sin(arg: T): T = arg.context.sin(arg) public fun <T : MathElement<out TrigonometricOperations<T>>> sin(arg: T): T = arg.context.sin(arg)
/** /**
* Computes the cosine of [arg]. * Computes the cosine of [arg].
*/ */
fun <T : MathElement<out TrigonometricOperations<T>>> cos(arg: T): T = arg.context.cos(arg) public fun <T : MathElement<out TrigonometricOperations<T>>> cos(arg: T): T = arg.context.cos(arg)
/** /**
* Computes the tangent of [arg]. * Computes the tangent of [arg].
*/ */
fun <T : MathElement<out TrigonometricOperations<T>>> tan(arg: T): T = arg.context.tan(arg) public fun <T : MathElement<out TrigonometricOperations<T>>> tan(arg: T): T = arg.context.tan(arg)
/** /**
* Computes the inverse sine of [arg]. * Computes the inverse sine of [arg].
*/ */
fun <T : MathElement<out TrigonometricOperations<T>>> asin(arg: T): T = arg.context.asin(arg) public fun <T : MathElement<out TrigonometricOperations<T>>> asin(arg: T): T = arg.context.asin(arg)
/** /**
* Computes the inverse cosine of [arg]. * Computes the inverse cosine of [arg].
*/ */
fun <T : MathElement<out TrigonometricOperations<T>>> acos(arg: T): T = arg.context.acos(arg) public fun <T : MathElement<out TrigonometricOperations<T>>> acos(arg: T): T = arg.context.acos(arg)
/** /**
* Computes the inverse tangent of [arg]. * Computes the inverse tangent of [arg].
*/ */
fun <T : MathElement<out TrigonometricOperations<T>>> atan(arg: T): T = arg.context.atan(arg) public fun <T : MathElement<out TrigonometricOperations<T>>> atan(arg: T): T = arg.context.atan(arg)
/** /**
* A container for hyperbolic trigonometric operations for specific type. * A container for hyperbolic trigonometric operations for specific type.
* *
* @param T the type of element of this structure. * @param T the type of element of this structure.
*/ */
interface HyperbolicOperations<T> : Algebra<T> { public interface HyperbolicOperations<T> : Algebra<T> {
/** /**
* Computes the hyperbolic sine of [arg]. * Computes the hyperbolic sine of [arg].
*/ */
fun sinh(arg: T): T public fun sinh(arg: T): T
/** /**
* Computes the hyperbolic cosine of [arg]. * Computes the hyperbolic cosine of [arg].
*/ */
fun cosh(arg: T): T public fun cosh(arg: T): T
/** /**
* Computes the hyperbolic tangent of [arg]. * Computes the hyperbolic tangent of [arg].
*/ */
fun tanh(arg: T): T public fun tanh(arg: T): T
/** /**
* Computes the inverse hyperbolic sine of [arg]. * Computes the inverse hyperbolic sine of [arg].
*/ */
fun asinh(arg: T): T public fun asinh(arg: T): T
/** /**
* Computes the inverse hyperbolic cosine of [arg]. * Computes the inverse hyperbolic cosine of [arg].
*/ */
fun acosh(arg: T): T public fun acosh(arg: T): T
/** /**
* Computes the inverse hyperbolic tangent of [arg]. * Computes the inverse hyperbolic tangent of [arg].
*/ */
fun atanh(arg: T): T public fun atanh(arg: T): T
companion object { public companion object {
/** /**
* The identifier of hyperbolic sine. * The identifier of hyperbolic sine.
*/ */
const val SINH_OPERATION: String = "sinh" public const val SINH_OPERATION: String = "sinh"
/** /**
* The identifier of hyperbolic cosine. * The identifier of hyperbolic cosine.
*/ */
const val COSH_OPERATION: String = "cosh" public const val COSH_OPERATION: String = "cosh"
/** /**
* The identifier of hyperbolic tangent. * The identifier of hyperbolic tangent.
*/ */
const val TANH_OPERATION: String = "tanh" public const val TANH_OPERATION: String = "tanh"
/** /**
* The identifier of inverse hyperbolic sine. * The identifier of inverse hyperbolic sine.
*/ */
const val ASINH_OPERATION: String = "asinh" public const val ASINH_OPERATION: String = "asinh"
/** /**
* The identifier of inverse hyperbolic cosine. * The identifier of inverse hyperbolic cosine.
*/ */
const val ACOSH_OPERATION: String = "acosh" public const val ACOSH_OPERATION: String = "acosh"
/** /**
* The identifier of inverse hyperbolic tangent. * The identifier of inverse hyperbolic tangent.
*/ */
const val ATANH_OPERATION: String = "atanh" public const val ATANH_OPERATION: String = "atanh"
} }
} }
/** /**
* Computes the hyperbolic sine of [arg]. * Computes the hyperbolic sine of [arg].
*/ */
fun <T : MathElement<out HyperbolicOperations<T>>> sinh(arg: T): T = arg.context.sinh(arg) public fun <T : MathElement<out HyperbolicOperations<T>>> sinh(arg: T): T = arg.context.sinh(arg)
/** /**
* Computes the hyperbolic cosine of [arg]. * Computes the hyperbolic cosine of [arg].
*/ */
fun <T : MathElement<out HyperbolicOperations<T>>> cosh(arg: T): T = arg.context.cosh(arg) public fun <T : MathElement<out HyperbolicOperations<T>>> cosh(arg: T): T = arg.context.cosh(arg)
/** /**
* Computes the hyperbolic tangent of [arg]. * Computes the hyperbolic tangent of [arg].
*/ */
fun <T : MathElement<out HyperbolicOperations<T>>> tanh(arg: T): T = arg.context.tanh(arg) public fun <T : MathElement<out HyperbolicOperations<T>>> tanh(arg: T): T = arg.context.tanh(arg)
/** /**
* Computes the inverse hyperbolic sine of [arg]. * Computes the inverse hyperbolic sine of [arg].
*/ */
fun <T : MathElement<out HyperbolicOperations<T>>> asinh(arg: T): T = arg.context.asinh(arg) public fun <T : MathElement<out HyperbolicOperations<T>>> asinh(arg: T): T = arg.context.asinh(arg)
/** /**
* Computes the inverse hyperbolic cosine of [arg]. * Computes the inverse hyperbolic cosine of [arg].
*/ */
fun <T : MathElement<out HyperbolicOperations<T>>> acosh(arg: T): T = arg.context.acosh(arg) public fun <T : MathElement<out HyperbolicOperations<T>>> acosh(arg: T): T = arg.context.acosh(arg)
/** /**
* Computes the inverse hyperbolic tangent of [arg]. * Computes the inverse hyperbolic tangent of [arg].
*/ */
fun <T : MathElement<out HyperbolicOperations<T>>> atanh(arg: T): T = arg.context.atanh(arg) public fun <T : MathElement<out HyperbolicOperations<T>>> atanh(arg: T): T = arg.context.atanh(arg)
/** /**
* A context extension to include power operations based on exponentiation. * A context extension to include power operations based on exponentiation.
* *
* @param T the type of element of this structure. * @param T the type of element of this structure.
*/ */
interface PowerOperations<T> : Algebra<T> { public interface PowerOperations<T> : Algebra<T> {
/** /**
* Raises [arg] to the power [pow]. * Raises [arg] to the power [pow].
*/ */
fun power(arg: T, pow: Number): T public fun power(arg: T, pow: Number): T
/** /**
* Computes the square root of the value [arg]. * Computes the square root of the value [arg].
*/ */
fun sqrt(arg: T): T = power(arg, 0.5) public fun sqrt(arg: T): T = power(arg, 0.5)
/** /**
* Raises this value to the power [pow]. * Raises this value to the power [pow].
*/ */
infix fun T.pow(pow: Number): T = power(this, pow) public infix fun T.pow(pow: Number): T = power(this, pow)
companion object { public companion object {
/** /**
* The identifier of exponentiation. * The identifier of exponentiation.
*/ */
const val POW_OPERATION: String = "pow" public const val POW_OPERATION: String = "pow"
/** /**
* The identifier of square root. * The identifier of square root.
*/ */
const val SQRT_OPERATION: String = "sqrt" public const val SQRT_OPERATION: String = "sqrt"
} }
} }
@ -239,56 +239,56 @@ interface PowerOperations<T> : Algebra<T> {
* @param power the exponent. * @param power the exponent.
* @return the base raised to the power. * @return the base raised to the power.
*/ */
infix fun <T : MathElement<out PowerOperations<T>>> T.pow(power: Double): T = context.power(this, power) public infix fun <T : MathElement<out PowerOperations<T>>> T.pow(power: Double): T = context.power(this, power)
/** /**
* Computes the square root of the value [arg]. * Computes the square root of the value [arg].
*/ */
fun <T : MathElement<out PowerOperations<T>>> sqrt(arg: T): T = arg pow 0.5 public fun <T : MathElement<out PowerOperations<T>>> sqrt(arg: T): T = arg pow 0.5
/** /**
* Computes the square of the value [arg]. * Computes the square of the value [arg].
*/ */
fun <T : MathElement<out PowerOperations<T>>> sqr(arg: T): T = arg pow 2.0 public fun <T : MathElement<out PowerOperations<T>>> sqr(arg: T): T = arg pow 2.0
/** /**
* A container for operations related to `exp` and `ln` functions. * A container for operations related to `exp` and `ln` functions.
* *
* @param T the type of element of this structure. * @param T the type of element of this structure.
*/ */
interface ExponentialOperations<T> : Algebra<T> { public interface ExponentialOperations<T> : Algebra<T> {
/** /**
* Computes Euler's number `e` raised to the power of the value [arg]. * Computes Euler's number `e` raised to the power of the value [arg].
*/ */
fun exp(arg: T): T public fun exp(arg: T): T
/** /**
* Computes the natural logarithm (base `e`) of the value [arg]. * Computes the natural logarithm (base `e`) of the value [arg].
*/ */
fun ln(arg: T): T public fun ln(arg: T): T
companion object { public companion object {
/** /**
* The identifier of exponential function. * The identifier of exponential function.
*/ */
const val EXP_OPERATION: String = "exp" public const val EXP_OPERATION: String = "exp"
/** /**
* The identifier of natural logarithm. * The identifier of natural logarithm.
*/ */
const val LN_OPERATION: String = "ln" public const val LN_OPERATION: String = "ln"
} }
} }
/** /**
* The identifier of exponential function. * The identifier of exponential function.
*/ */
fun <T : MathElement<out ExponentialOperations<T>>> exp(arg: T): T = arg.context.exp(arg) public fun <T : MathElement<out ExponentialOperations<T>>> exp(arg: T): T = arg.context.exp(arg)
/** /**
* The identifier of natural logarithm. * The identifier of natural logarithm.
*/ */
fun <T : MathElement<out ExponentialOperations<T>>> ln(arg: T): T = arg.context.ln(arg) public fun <T : MathElement<out ExponentialOperations<T>>> ln(arg: T): T = arg.context.ln(arg)
/** /**
* A container for norm functional on element. * A container for norm functional on element.
@ -296,14 +296,14 @@ fun <T : MathElement<out ExponentialOperations<T>>> ln(arg: T): T = arg.context.
* @param T the type of element having norm defined. * @param T the type of element having norm defined.
* @param R the type of norm. * @param R the type of norm.
*/ */
interface Norm<in T : Any, out R> { public interface Norm<in T : Any, out R> {
/** /**
* Computes the norm of [arg] (i.e. absolute value or vector length). * Computes the norm of [arg] (i.e. absolute value or vector length).
*/ */
fun norm(arg: T): R public fun norm(arg: T): R
} }
/** /**
* Computes the norm of [arg] (i.e. absolute value or vector length). * Computes the norm of [arg] (i.e. absolute value or vector length).
*/ */
fun <T : MathElement<out Norm<T, R>>, R> norm(arg: T): R = arg.context.norm(arg) public fun <T : MathElement<out Norm<T, R>>, R> norm(arg: T): R = arg.context.norm(arg)

View File

@ -3,16 +3,16 @@ package scientifik.kmath.structures
import scientifik.kmath.operations.Field import scientifik.kmath.operations.Field
import scientifik.kmath.operations.FieldElement import scientifik.kmath.operations.FieldElement
class BoxingNDField<T, F : Field<T>>( public class BoxingNDField<T, F : Field<T>>(
override val shape: IntArray, override val shape: IntArray,
override val elementContext: F, override val elementContext: F,
val bufferFactory: BufferFactory<T> public val bufferFactory: BufferFactory<T>
) : BufferedNDField<T, F> { ) : BufferedNDField<T, F> {
override val zero: BufferedNDFieldElement<T, F> by lazy { produce { zero } } override val zero: BufferedNDFieldElement<T, F> by lazy { produce { zero } }
override val one: BufferedNDFieldElement<T, F> by lazy { produce { one } } override val one: BufferedNDFieldElement<T, F> by lazy { produce { one } }
override val strides: Strides = DefaultStrides(shape) override val strides: Strides = DefaultStrides(shape)
fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> =
bufferFactory(size, initializer) bufferFactory(size, initializer)
override fun check(vararg elements: NDBuffer<T>) { override fun check(vararg elements: NDBuffer<T>) {
@ -70,7 +70,7 @@ class BoxingNDField<T, F : Field<T>>(
BufferedNDFieldElement(this@BoxingNDField, buffer) BufferedNDFieldElement(this@BoxingNDField, buffer)
} }
inline fun <T : Any, F : Field<T>, R> F.nd( public inline fun <T : Any, F : Field<T>, R> F.nd(
noinline bufferFactory: BufferFactory<T>, noinline bufferFactory: BufferFactory<T>,
vararg shape: Int, vararg shape: Int,
action: NDField<T, F, *>.() -> R action: NDField<T, F, *>.() -> R

View File

@ -3,16 +3,16 @@ package scientifik.kmath.structures
import scientifik.kmath.operations.Ring import scientifik.kmath.operations.Ring
import scientifik.kmath.operations.RingElement import scientifik.kmath.operations.RingElement
class BoxingNDRing<T, R : Ring<T>>( public class BoxingNDRing<T, R : Ring<T>>(
override val shape: IntArray, override val shape: IntArray,
override val elementContext: R, override val elementContext: R,
val bufferFactory: BufferFactory<T> public val bufferFactory: BufferFactory<T>
) : BufferedNDRing<T, R> { ) : BufferedNDRing<T, R> {
override val strides: Strides = DefaultStrides(shape) override val strides: Strides = DefaultStrides(shape)
override val zero: BufferedNDRingElement<T, R> by lazy { produce { zero } } override val zero: BufferedNDRingElement<T, R> by lazy { produce { zero } }
override val one: BufferedNDRingElement<T, R> by lazy { produce { one } } override val one: BufferedNDRingElement<T, R> by lazy { produce { one } }
fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = bufferFactory(size, initializer) public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = bufferFactory(size, initializer)
override fun check(vararg elements: NDBuffer<T>) { override fun check(vararg elements: NDBuffer<T>) {
require(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" } require(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" }

View File

@ -5,24 +5,23 @@ import kotlin.reflect.KClass
/** /**
* A context that allows to operate on a [MutableBuffer] as on 2d array * A context that allows to operate on a [MutableBuffer] as on 2d array
*/ */
class BufferAccessor2D<T : Any>(val type: KClass<T>, val rowNum: Int, val colNum: Int) { public class BufferAccessor2D<T : Any>(public val type: KClass<T>, public val rowNum: Int, public val colNum: Int) {
operator fun Buffer<T>.get(i: Int, j: Int): T = get(i + colNum * j) public operator fun Buffer<T>.get(i: Int, j: Int): T = get(i + colNum * j)
operator fun MutableBuffer<T>.set(i: Int, j: Int, value: T) { public operator fun MutableBuffer<T>.set(i: Int, j: Int, value: T) {
set(i + colNum * j, value) set(i + colNum * j, value)
} }
inline fun create(init: (i: Int, j: Int) -> T): MutableBuffer<T> = public inline fun create(init: (i: Int, j: Int) -> T): MutableBuffer<T> =
MutableBuffer.auto(type, rowNum * colNum) { offset -> init(offset / colNum, offset % colNum) } MutableBuffer.auto(type, rowNum * colNum) { offset -> init(offset / colNum, offset % colNum) }
fun create(mat: Structure2D<T>): MutableBuffer<T> = create { i, j -> mat[i, j] } public fun create(mat: Structure2D<T>): MutableBuffer<T> = create { i, j -> mat[i, j] }
//TODO optimize wrapper //TODO optimize wrapper
fun MutableBuffer<T>.collect(): Structure2D<T> = public fun MutableBuffer<T>.collect(): Structure2D<T> =
NDStructure.auto(type, rowNum, colNum) { (i, j) -> get(i, j) }.as2D() NDStructure.auto(type, rowNum, colNum) { (i, j) -> get(i, j) }.as2D()
public inner class Row(public val buffer: MutableBuffer<T>, public val rowIndex: Int) : MutableBuffer<T> {
inner class Row(val buffer: MutableBuffer<T>, val rowIndex: Int) : MutableBuffer<T> {
override val size: Int get() = colNum override val size: Int get() = colNum
override operator fun get(index: Int): T = buffer[rowIndex, index] override operator fun get(index: Int): T = buffer[rowIndex, index]
@ -39,5 +38,5 @@ class BufferAccessor2D<T : Any>(val type: KClass<T>, val rowNum: Int, val colNum
/** /**
* Get row * Get row
*/ */
fun MutableBuffer<T>.row(i: Int): Row = Row(this, i) public fun MutableBuffer<T>.row(i: Int): Row = Row(this, i)
} }

View File

@ -2,8 +2,8 @@ package scientifik.kmath.structures
import scientifik.kmath.operations.* import scientifik.kmath.operations.*
interface BufferedNDAlgebra<T, C> : NDAlgebra<T, C, NDBuffer<T>> { public interface BufferedNDAlgebra<T, C> : NDAlgebra<T, C, NDBuffer<T>> {
val strides: Strides public val strides: Strides
override fun check(vararg elements: NDBuffer<T>): Unit = override fun check(vararg elements: NDBuffer<T>): Unit =
require(elements.all { it.strides == strides }) { ("Strides mismatch") } require(elements.all { it.strides == strides }) { ("Strides mismatch") }
@ -15,29 +15,27 @@ interface BufferedNDAlgebra<T, C> : NDAlgebra<T, C, NDBuffer<T>> {
* *
* If the argument is [NDBuffer] with different strides structure, the new element will be produced. * If the argument is [NDBuffer] with different strides structure, the new element will be produced.
*/ */
fun NDStructure<T>.toBuffer(): NDBuffer<T> { public fun NDStructure<T>.toBuffer(): NDBuffer<T> =
return if (this is NDBuffer<T> && this.strides == this@BufferedNDAlgebra.strides) { if (this is NDBuffer<T> && this.strides == this@BufferedNDAlgebra.strides)
this this
} else { else
produce { index -> get(index) } produce { index -> this@toBuffer[index] }
}
}
/** /**
* Convert a buffer to element of this algebra * Convert a buffer to element of this algebra
*/ */
fun NDBuffer<T>.toElement(): MathElement<out BufferedNDAlgebra<T, C>> public fun NDBuffer<T>.toElement(): MathElement<out BufferedNDAlgebra<T, C>>
} }
interface BufferedNDSpace<T, S : Space<T>> : NDSpace<T, S, NDBuffer<T>>, BufferedNDAlgebra<T, S> { public interface BufferedNDSpace<T, S : Space<T>> : NDSpace<T, S, NDBuffer<T>>, BufferedNDAlgebra<T, S> {
override fun NDBuffer<T>.toElement(): SpaceElement<NDBuffer<T>, *, out BufferedNDSpace<T, S>> override fun NDBuffer<T>.toElement(): SpaceElement<NDBuffer<T>, *, out BufferedNDSpace<T, S>>
} }
interface BufferedNDRing<T, R : Ring<T>> : NDRing<T, R, NDBuffer<T>>, BufferedNDSpace<T, R> { public interface BufferedNDRing<T, R : Ring<T>> : NDRing<T, R, NDBuffer<T>>, BufferedNDSpace<T, R> {
override fun NDBuffer<T>.toElement(): RingElement<NDBuffer<T>, *, out BufferedNDRing<T, R>> override fun NDBuffer<T>.toElement(): RingElement<NDBuffer<T>, *, out BufferedNDRing<T, R>>
} }
interface BufferedNDField<T, F : Field<T>> : NDField<T, F, NDBuffer<T>>, BufferedNDRing<T, F> { public interface BufferedNDField<T, F : Field<T>> : NDField<T, F, NDBuffer<T>>, BufferedNDRing<T, F> {
override fun NDBuffer<T>.toElement(): FieldElement<NDBuffer<T>, *, out BufferedNDField<T, F>> override fun NDBuffer<T>.toElement(): FieldElement<NDBuffer<T>, *, out BufferedNDField<T, F>>
} }

View File

@ -5,7 +5,7 @@ import scientifik.kmath.operations.*
/** /**
* Base class for an element with context, containing strides * Base class for an element with context, containing strides
*/ */
abstract class BufferedNDElement<T, C> : NDBuffer<T>(), NDElement<T, C, NDBuffer<T>> { public abstract class BufferedNDElement<T, C> : NDBuffer<T>(), NDElement<T, C, NDBuffer<T>> {
abstract override val context: BufferedNDAlgebra<T, C> abstract override val context: BufferedNDAlgebra<T, C>
override val strides: Strides get() = context.strides override val strides: Strides get() = context.strides
@ -13,7 +13,7 @@ abstract class BufferedNDElement<T, C> : NDBuffer<T>(), NDElement<T, C, NDBuffer
override val shape: IntArray get() = context.shape override val shape: IntArray get() = context.shape
} }
class BufferedNDSpaceElement<T, S : Space<T>>( public class BufferedNDSpaceElement<T, S : Space<T>>(
override val context: BufferedNDSpace<T, S>, override val context: BufferedNDSpace<T, S>,
override val buffer: Buffer<T> override val buffer: Buffer<T>
) : BufferedNDElement<T, S>(), SpaceElement<NDBuffer<T>, BufferedNDSpaceElement<T, S>, BufferedNDSpace<T, S>> { ) : BufferedNDElement<T, S>(), SpaceElement<NDBuffer<T>, BufferedNDSpaceElement<T, S>, BufferedNDSpace<T, S>> {
@ -26,7 +26,7 @@ class BufferedNDSpaceElement<T, S : Space<T>>(
} }
} }
class BufferedNDRingElement<T, R : Ring<T>>( public class BufferedNDRingElement<T, R : Ring<T>>(
override val context: BufferedNDRing<T, R>, override val context: BufferedNDRing<T, R>,
override val buffer: Buffer<T> override val buffer: Buffer<T>
) : BufferedNDElement<T, R>(), RingElement<NDBuffer<T>, BufferedNDRingElement<T, R>, BufferedNDRing<T, R>> { ) : BufferedNDElement<T, R>(), RingElement<NDBuffer<T>, BufferedNDRingElement<T, R>, BufferedNDRing<T, R>> {
@ -38,7 +38,7 @@ class BufferedNDRingElement<T, R : Ring<T>>(
} }
} }
class BufferedNDFieldElement<T, F : Field<T>>( public class BufferedNDFieldElement<T, F : Field<T>>(
override val context: BufferedNDField<T, F>, override val context: BufferedNDField<T, F>,
override val buffer: Buffer<T> override val buffer: Buffer<T>
) : BufferedNDElement<T, F>(), FieldElement<NDBuffer<T>, BufferedNDFieldElement<T, F>, BufferedNDField<T, F>> { ) : BufferedNDElement<T, F>(), FieldElement<NDBuffer<T>, BufferedNDFieldElement<T, F>, BufferedNDField<T, F>> {
@ -54,7 +54,7 @@ class BufferedNDFieldElement<T, F : Field<T>>(
/** /**
* Element by element application of any operation on elements to the whole array. Just like in numpy. * Element by element application of any operation on elements to the whole array. Just like in numpy.
*/ */
operator fun <T : Any, F : Field<T>> Function1<T, T>.invoke(ndElement: BufferedNDElement<T, F>): MathElement<out BufferedNDAlgebra<T, F>> = public operator fun <T : Any, F : Field<T>> Function1<T, T>.invoke(ndElement: BufferedNDElement<T, F>): MathElement<out BufferedNDAlgebra<T, F>> =
ndElement.context.run { map(ndElement) { invoke(it) }.toElement() } ndElement.context.run { map(ndElement) { invoke(it) }.toElement() }
/* plus and minus */ /* plus and minus */
@ -62,13 +62,13 @@ operator fun <T : Any, F : Field<T>> Function1<T, T>.invoke(ndElement: BufferedN
/** /**
* Summation operation for [BufferedNDElement] and single element * Summation operation for [BufferedNDElement] and single element
*/ */
operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.plus(arg: T): NDElement<T, F, NDBuffer<T>> = public operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.plus(arg: T): NDElement<T, F, NDBuffer<T>> =
context.map(this) { it + arg }.wrap() context.map(this) { it + arg }.wrap()
/** /**
* Subtraction operation between [BufferedNDElement] and single element * Subtraction operation between [BufferedNDElement] and single element
*/ */
operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.minus(arg: T): NDElement<T, F, NDBuffer<T>> = public operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.minus(arg: T): NDElement<T, F, NDBuffer<T>> =
context.map(this) { it - arg }.wrap() context.map(this) { it - arg }.wrap()
/* prod and div */ /* prod and div */
@ -76,11 +76,11 @@ operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.minus(arg: T): NDEl
/** /**
* Product operation for [BufferedNDElement] and single element * Product operation for [BufferedNDElement] and single element
*/ */
operator fun <T : Any, F : Ring<T>> BufferedNDElement<T, F>.times(arg: T): NDElement<T, F, NDBuffer<T>> = public operator fun <T : Any, F : Ring<T>> BufferedNDElement<T, F>.times(arg: T): NDElement<T, F, NDBuffer<T>> =
context.map(this) { it * arg }.wrap() context.map(this) { it * arg }.wrap()
/** /**
* Division operation between [BufferedNDElement] and single element * Division operation between [BufferedNDElement] and single element
*/ */
operator fun <T : Any, F : Field<T>> BufferedNDElement<T, F>.div(arg: T): NDElement<T, F, NDBuffer<T>> = public operator fun <T : Any, F : Field<T>> BufferedNDElement<T, F>.div(arg: T): NDElement<T, F, NDBuffer<T>> =
context.map(this) { it / arg }.wrap() context.map(this) { it / arg }.wrap()

View File

@ -11,44 +11,44 @@ import kotlin.reflect.KClass
* *
* @param T the type of buffer. * @param T the type of buffer.
*/ */
typealias BufferFactory<T> = (Int, (Int) -> T) -> Buffer<T> public typealias BufferFactory<T> = (Int, (Int) -> T) -> Buffer<T>
/** /**
* Function that produces [MutableBuffer] from its size and function that supplies values. * Function that produces [MutableBuffer] from its size and function that supplies values.
* *
* @param T the type of buffer. * @param T the type of buffer.
*/ */
typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T> public typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T>
/** /**
* A generic immutable random-access structure for both primitives and objects. * A generic immutable random-access structure for both primitives and objects.
* *
* @param T the type of elements contained in the buffer. * @param T the type of elements contained in the buffer.
*/ */
interface Buffer<T> { public interface Buffer<T> {
/** /**
* The size of this buffer. * The size of this buffer.
*/ */
val size: Int public val size: Int
/** /**
* Gets element at given index. * Gets element at given index.
*/ */
operator fun get(index: Int): T public operator fun get(index: Int): T
/** /**
* Iterates over all elements. * Iterates over all elements.
*/ */
operator fun iterator(): Iterator<T> public operator fun iterator(): Iterator<T>
/** /**
* Checks content equality with another buffer. * Checks content equality with another buffer.
*/ */
fun contentEquals(other: Buffer<*>): Boolean = public fun contentEquals(other: Buffer<*>): Boolean =
asSequence().mapIndexed { index, value -> value == other[index] }.all { it } asSequence().mapIndexed { index, value -> value == other[index] }.all { it }
companion object { public companion object {
inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer { public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer {
val array = DoubleArray(size) { initializer(it) } val array = DoubleArray(size) { initializer(it) }
return RealBuffer(array) return RealBuffer(array)
} }
@ -56,10 +56,10 @@ interface Buffer<T> {
/** /**
* Create a boxing buffer of given type * Create a boxing buffer of given type
*/ */
inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> = ListBuffer(List(size, initializer)) public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> = ListBuffer(List(size, initializer))
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
inline fun <T : Any> auto(type: KClass<T>, size: Int, crossinline initializer: (Int) -> T): Buffer<T> { public inline fun <T : Any> auto(type: KClass<T>, size: Int, crossinline initializer: (Int) -> T): Buffer<T> {
//TODO add resolution based on Annotation or companion resolution //TODO add resolution based on Annotation or companion resolution
return when (type) { return when (type) {
Double::class -> RealBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer<T> Double::class -> RealBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer<T>
@ -75,7 +75,7 @@ interface Buffer<T> {
* Create most appropriate immutable buffer for given type avoiding boxing wherever possible * Create most appropriate immutable buffer for given type avoiding boxing wherever possible
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> auto(size: Int, crossinline initializer: (Int) -> T): Buffer<T> = public inline fun <reified T : Any> auto(size: Int, crossinline initializer: (Int) -> T): Buffer<T> =
auto(T::class, size, initializer) auto(T::class, size, initializer)
} }
} }
@ -83,35 +83,35 @@ interface Buffer<T> {
/** /**
* Creates a sequence that returns all elements from this [Buffer]. * Creates a sequence that returns all elements from this [Buffer].
*/ */
fun <T> Buffer<T>.asSequence(): Sequence<T> = Sequence(::iterator) public fun <T> Buffer<T>.asSequence(): Sequence<T> = Sequence(::iterator)
/** /**
* Creates an iterable that returns all elements from this [Buffer]. * Creates an iterable that returns all elements from this [Buffer].
*/ */
fun <T> Buffer<T>.asIterable(): Iterable<T> = Iterable(::iterator) public fun <T> Buffer<T>.asIterable(): Iterable<T> = Iterable(::iterator)
/** /**
* Returns an [IntRange] of the valid indices for this [Buffer]. * Returns an [IntRange] of the valid indices for this [Buffer].
*/ */
val Buffer<*>.indices: IntRange get() = 0 until size public val Buffer<*>.indices: IntRange get() = 0 until size
/** /**
* A generic mutable random-access structure for both primitives and objects. * A generic mutable random-access structure for both primitives and objects.
* *
* @param T the type of elements contained in the buffer. * @param T the type of elements contained in the buffer.
*/ */
interface MutableBuffer<T> : Buffer<T> { public interface MutableBuffer<T> : Buffer<T> {
/** /**
* Sets the array element at the specified [index] to the specified [value]. * Sets the array element at the specified [index] to the specified [value].
*/ */
operator fun set(index: Int, value: T) public operator fun set(index: Int, value: T)
/** /**
* Returns a shallow copy of the buffer. * Returns a shallow copy of the buffer.
*/ */
fun copy(): MutableBuffer<T> public fun copy(): MutableBuffer<T>
companion object { public companion object {
/** /**
* Create a boxing mutable buffer of given type * Create a boxing mutable buffer of given type
*/ */
@ -216,7 +216,7 @@ class ArrayBuffer<T>(private val array: Array<T>) : MutableBuffer<T> {
/** /**
* Returns an [ArrayBuffer] that wraps the original array. * Returns an [ArrayBuffer] that wraps the original array.
*/ */
fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this) public fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
/** /**
* Immutable wrapper for [MutableBuffer]. * Immutable wrapper for [MutableBuffer].
@ -224,7 +224,7 @@ fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
* @param T the type of elements contained in the buffer. * @param T the type of elements contained in the buffer.
* @property buffer The underlying buffer. * @property buffer The underlying buffer.
*/ */
inline class ReadOnlyBuffer<T>(val buffer: MutableBuffer<T>) : Buffer<T> { public inline class ReadOnlyBuffer<T>(public val buffer: MutableBuffer<T>) : Buffer<T> {
override val size: Int get() = buffer.size override val size: Int get() = buffer.size
override operator fun get(index: Int): T = buffer[index] override operator fun get(index: Int): T = buffer[index]
@ -238,7 +238,7 @@ inline class ReadOnlyBuffer<T>(val buffer: MutableBuffer<T>) : Buffer<T> {
* *
* @param T the type of elements provided by the buffer. * @param T the type of elements provided by the buffer.
*/ */
class VirtualBuffer<T>(override val size: Int, private val generator: (Int) -> T) : Buffer<T> { public class VirtualBuffer<T>(override val size: Int, private val generator: (Int) -> T) : Buffer<T> {
override operator fun get(index: Int): T { override operator fun get(index: Int): T {
if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index") if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index")
return generator(index) return generator(index)
@ -258,14 +258,14 @@ class VirtualBuffer<T>(override val size: Int, private val generator: (Int) -> T
/** /**
* Convert this buffer to read-only buffer. * Convert this buffer to read-only buffer.
*/ */
fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this
/** /**
* Typealias for buffer transformations. * Typealias for buffer transformations.
*/ */
typealias BufferTransform<T, R> = (Buffer<T>) -> Buffer<R> public typealias BufferTransform<T, R> = (Buffer<T>) -> Buffer<R>
/** /**
* Typealias for buffer transformations with suspend function. * Typealias for buffer transformations with suspend function.
*/ */
typealias SuspendBufferTransform<T, R> = suspend (Buffer<T>) -> Buffer<R> public typealias SuspendBufferTransform<T, R> = suspend (Buffer<T>) -> Buffer<R>

View File

@ -8,12 +8,12 @@ import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
typealias ComplexNDElement = BufferedNDFieldElement<Complex, ComplexField> public typealias ComplexNDElement = BufferedNDFieldElement<Complex, ComplexField>
/** /**
* An optimized nd-field for complex numbers * An optimized nd-field for complex numbers
*/ */
class ComplexNDField(override val shape: IntArray) : public class ComplexNDField(override val shape: IntArray) :
BufferedNDField<Complex, ComplexField>, BufferedNDField<Complex, ComplexField>,
ExtendedNDField<Complex, ComplexField, NDBuffer<Complex>> { ExtendedNDField<Complex, ComplexField, NDBuffer<Complex>> {
@ -22,7 +22,7 @@ class ComplexNDField(override val shape: IntArray) :
override val zero: ComplexNDElement by lazy { produce { zero } } override val zero: ComplexNDElement by lazy { produce { zero } }
override val one: ComplexNDElement by lazy { produce { one } } override val one: ComplexNDElement by lazy { produce { one } }
inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Complex): Buffer<Complex> = public inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Complex): Buffer<Complex> =
Buffer.complex(size) { initializer(it) } Buffer.complex(size) { initializer(it) }
/** /**
@ -130,29 +130,25 @@ operator fun Function1<Complex, Complex>.invoke(ndElement: ComplexNDElement): Co
/** /**
* Summation operation for [BufferedNDElement] and single element * Summation operation for [BufferedNDElement] and single element
*/ */
operator fun ComplexNDElement.plus(arg: Complex): ComplexNDElement = map { it + arg } public operator fun ComplexNDElement.plus(arg: Complex): ComplexNDElement = map { it + arg }
/** /**
* Subtraction operation between [BufferedNDElement] and single element * Subtraction operation between [BufferedNDElement] and single element
*/ */
operator fun ComplexNDElement.minus(arg: Complex): ComplexNDElement = public operator fun ComplexNDElement.minus(arg: Complex): ComplexNDElement = map { it - arg }
map { it - arg }
operator fun ComplexNDElement.plus(arg: Double): ComplexNDElement = public operator fun ComplexNDElement.plus(arg: Double): ComplexNDElement = map { it + arg }
map { it + arg } public operator fun ComplexNDElement.minus(arg: Double): ComplexNDElement = map { it - arg }
operator fun ComplexNDElement.minus(arg: Double): ComplexNDElement = public fun NDField.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape)
map { it - arg }
fun NDField.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape) public fun NDElement.Companion.complex(vararg shape: Int, initializer: ComplexField.(IntArray) -> Complex): ComplexNDElement =
fun NDElement.Companion.complex(vararg shape: Int, initializer: ComplexField.(IntArray) -> Complex): ComplexNDElement =
NDField.complex(*shape).produce(initializer) NDField.complex(*shape).produce(initializer)
/** /**
* Produce a context for n-dimensional operations inside this real field * Produce a context for n-dimensional operations inside this real field
*/ */
inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R { public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R {
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
return NDField.complex(*shape).action() return NDField.complex(*shape).action()
} }

View File

@ -9,7 +9,7 @@ import scientifik.kmath.operations.ExtendedField
* @param N the type of ND structure. * @param N the type of ND structure.
* @param F the extended field of structure elements. * @param F the extended field of structure elements.
*/ */
interface ExtendedNDField<T : Any, F : ExtendedField<T>, N : NDStructure<T>> : NDField<T, F, N>, ExtendedField<N> public interface ExtendedNDField<T : Any, F : ExtendedField<T>, N : NDStructure<T>> : NDField<T, F, N>, ExtendedField<N>
///** ///**
// * NDField that supports [ExtendedField] operations on its elements // * NDField that supports [ExtendedField] operations on its elements

View File

@ -9,7 +9,7 @@ import kotlin.experimental.and
* *
* @property mask bit mask value of this flag. * @property mask bit mask value of this flag.
*/ */
enum class ValueFlag(val mask: Byte) { public enum class ValueFlag(public val mask: Byte) {
/** /**
* Reports the value is NaN. * Reports the value is NaN.
*/ */

View File

@ -9,7 +9,7 @@ import kotlin.contracts.contract
* *
* @property array the underlying array. * @property array the underlying array.
*/ */
inline class IntBuffer(val array: IntArray) : MutableBuffer<Int> { public inline class IntBuffer(public val array: IntArray) : MutableBuffer<Int> {
override val size: Int get() = array.size override val size: Int get() = array.size
override operator fun get(index: Int): Int = array[index] override operator fun get(index: Int): Int = array[index]

View File

@ -8,7 +8,7 @@ import kotlin.contracts.contract
* *
* @property array the underlying array. * @property array the underlying array.
*/ */
inline class LongBuffer(val array: LongArray) : MutableBuffer<Long> { public inline class LongBuffer(public val array: LongArray) : MutableBuffer<Long> {
override val size: Int get() = array.size override val size: Int get() = array.size
override operator fun get(index: Int): Long = array[index] override operator fun get(index: Int): Long = array[index]
@ -31,7 +31,7 @@ inline class LongBuffer(val array: LongArray) : MutableBuffer<Long> {
* The function [init] is called for each array element sequentially starting from the first one. * The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an buffer element given its index. * It should return the value for an buffer element given its index.
*/ */
inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer { public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer {
contract { callsInPlace(init) } contract { callsInPlace(init) }
return LongBuffer(LongArray(size) { init(it) }) return LongBuffer(LongArray(size) { init(it) })
} }
@ -39,12 +39,12 @@ inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer {
/** /**
* Returns a new [LongBuffer] of given elements. * Returns a new [LongBuffer] of given elements.
*/ */
fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs) public fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs)
/** /**
* Returns a [IntArray] containing all of the elements of this [MutableBuffer]. * Returns a [IntArray] containing all of the elements of this [MutableBuffer].
*/ */
val MutableBuffer<out Long>.array: LongArray public val MutableBuffer<out Long>.array: LongArray
get() = (if (this is LongBuffer) array else LongArray(size) { get(it) }) get() = (if (this is LongBuffer) array else LongArray(size) { get(it) })
/** /**
@ -53,4 +53,4 @@ val MutableBuffer<out Long>.array: LongArray
* @receiver the array. * @receiver the array.
* @return the new buffer. * @return the new buffer.
*/ */
fun LongArray.asBuffer(): LongBuffer = LongBuffer(this) public fun LongArray.asBuffer(): LongBuffer = LongBuffer(this)

View File

@ -5,12 +5,10 @@ import scientifik.kmath.operations.Field
import scientifik.kmath.operations.Ring import scientifik.kmath.operations.Ring
import scientifik.kmath.operations.Space import scientifik.kmath.operations.Space
/** /**
* An exception is thrown when the expected ans actual shape of NDArray differs * An exception is thrown when the expected ans actual shape of NDArray differs
*/ */
class ShapeMismatchException(val expected: IntArray, val actual: IntArray) : RuntimeException() public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) : RuntimeException()
/** /**
* The base interface for all nd-algebra implementations * The base interface for all nd-algebra implementations
@ -18,53 +16,49 @@ class ShapeMismatchException(val expected: IntArray, val actual: IntArray) : Run
* @param C the type of the element context * @param C the type of the element context
* @param N the type of the structure * @param N the type of the structure
*/ */
interface NDAlgebra<T, C, N : NDStructure<T>> { public interface NDAlgebra<T, C, N : NDStructure<T>> {
val shape: IntArray public val shape: IntArray
val elementContext: C public val elementContext: C
/** /**
* Produce a new [N] structure using given initializer function * Produce a new [N] structure using given initializer function
*/ */
fun produce(initializer: C.(IntArray) -> T): N public fun produce(initializer: C.(IntArray) -> T): N
/** /**
* Map elements from one structure to another one * Map elements from one structure to another one
*/ */
fun map(arg: N, transform: C.(T) -> T): N public fun map(arg: N, transform: C.(T) -> T): N
/** /**
* Map indexed elements * Map indexed elements
*/ */
fun mapIndexed(arg: N, transform: C.(index: IntArray, T) -> T): N public fun mapIndexed(arg: N, transform: C.(index: IntArray, T) -> T): N
/** /**
* Combine two structures into one * Combine two structures into one
*/ */
fun combine(a: N, b: N, transform: C.(T, T) -> T): N public fun combine(a: N, b: N, transform: C.(T, T) -> T): N
/** /**
* Check if given elements are consistent with this context * Check if given elements are consistent with this context
*/ */
fun check(vararg elements: N) { public fun check(vararg elements: N): Unit = elements.forEach {
elements.forEach { if (!shape.contentEquals(it.shape)) throw ShapeMismatchException(shape, it.shape)
if (!shape.contentEquals(it.shape)) {
throw ShapeMismatchException(shape, it.shape)
}
}
} }
/** /**
* element-by-element invoke a function working on [T] on a [NDStructure] * element-by-element invoke a function working on [T] on a [NDStructure]
*/ */
operator fun Function1<T, T>.invoke(structure: N): N = map(structure) { value -> this@invoke(value) } public operator fun Function1<T, T>.invoke(structure: N): N = map(structure) { value -> this@invoke(value) }
companion object public companion object
} }
/** /**
* An nd-space over element space * An nd-space over element space
*/ */
interface NDSpace<T, S : Space<T>, N : NDStructure<T>> : Space<N>, NDAlgebra<T, S, N> { public interface NDSpace<T, S : Space<T>, N : NDStructure<T>> : Space<N>, NDAlgebra<T, S, N> {
/** /**
* Element-by-element addition * Element-by-element addition
*/ */
@ -76,32 +70,31 @@ interface NDSpace<T, S : Space<T>, N : NDStructure<T>> : Space<N>, NDAlgebra<T,
override fun multiply(a: N, k: Number): N = map(a) { multiply(it, k) } override fun multiply(a: N, k: Number): N = map(a) { multiply(it, k) }
//TODO move to extensions after KEEP-176 //TODO move to extensions after KEEP-176
operator fun N.plus(arg: T): N = map(this) { value -> add(arg, value) } public operator fun N.plus(arg: T): N = map(this) { value -> add(arg, value) }
operator fun N.minus(arg: T): N = map(this) { value -> add(arg, -value) } public operator fun N.minus(arg: T): N = map(this) { value -> add(arg, -value) }
operator fun T.plus(arg: N): N = map(arg) { value -> add(this@plus, value) } public operator fun T.plus(arg: N): N = map(arg) { value -> add(this@plus, value) }
operator fun T.minus(arg: N): N = map(arg) { value -> add(-this@minus, value) } public operator fun T.minus(arg: N): N = map(arg) { value -> add(-this@minus, value) }
companion object public companion object
} }
/** /**
* An nd-ring over element ring * An nd-ring over element ring
*/ */
interface NDRing<T, R : Ring<T>, N : NDStructure<T>> : Ring<N>, NDSpace<T, R, N> { public interface NDRing<T, R : Ring<T>, N : NDStructure<T>> : Ring<N>, NDSpace<T, R, N> {
/** /**
* Element-by-element multiplication * Element-by-element multiplication
*/ */
override fun multiply(a: N, b: N): N = combine(a, b) { aValue, bValue -> multiply(aValue, bValue) } override fun multiply(a: N, b: N): N = combine(a, b) { aValue, bValue -> multiply(aValue, bValue) }
//TODO move to extensions after KEEP-176 //TODO move to extensions after KEEP-176
operator fun N.times(arg: T): N = map(this) { value -> multiply(arg, value) } public operator fun N.times(arg: T): N = map(this) { value -> multiply(arg, value) }
operator fun T.times(arg: N): N = map(arg) { value -> multiply(this@times, value) } public operator fun T.times(arg: N): N = map(arg) { value -> multiply(this@times, value) }
companion object public companion object
} }
/** /**
@ -111,17 +104,16 @@ interface NDRing<T, R : Ring<T>, N : NDStructure<T>> : Ring<N>, NDSpace<T, R, N>
* @param N the type of ND structure. * @param N the type of ND structure.
* @param F field of structure elements. * @param F field of structure elements.
*/ */
interface NDField<T, F : Field<T>, N : NDStructure<T>> : Field<N>, NDRing<T, F, N> { public interface NDField<T, F : Field<T>, N : NDStructure<T>> : Field<N>, NDRing<T, F, N> {
/** /**
* Element-by-element division * Element-by-element division
*/ */
override fun divide(a: N, b: N): N = combine(a, b) { aValue, bValue -> divide(aValue, bValue) } override fun divide(a: N, b: N): N = combine(a, b) { aValue, bValue -> divide(aValue, bValue) }
//TODO move to extensions after KEEP-176 //TODO move to extensions after KEEP-176
operator fun N.div(arg: T): N = map(this) { value -> divide(arg, value) } public operator fun N.div(arg: T): N = map(this) { value -> divide(arg, value) }
operator fun T.div(arg: N): N = map(arg) { divide(it, this@div) } public operator fun T.div(arg: N): N = map(arg) { divide(it, this@div) }
companion object { companion object {

View File

@ -3,9 +3,9 @@ package scientifik.kmath.structures
import scientifik.kmath.operations.FieldElement import scientifik.kmath.operations.FieldElement
import scientifik.kmath.operations.RealField import scientifik.kmath.operations.RealField
typealias RealNDElement = BufferedNDFieldElement<Double, RealField> public typealias RealNDElement = BufferedNDFieldElement<Double, RealField>
class RealNDField(override val shape: IntArray) : public class RealNDField(override val shape: IntArray) :
BufferedNDField<Double, RealField>, BufferedNDField<Double, RealField>,
ExtendedNDField<Double, RealField, NDBuffer<Double>> { ExtendedNDField<Double, RealField, NDBuffer<Double>> {
@ -15,7 +15,7 @@ class RealNDField(override val shape: IntArray) :
override val zero: RealNDElement by lazy { produce { zero } } override val zero: RealNDElement by lazy { produce { zero } }
override val one: RealNDElement by lazy { produce { one } } override val one: RealNDElement by lazy { produce { one } }
inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer<Double> = public inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer<Double> =
RealBuffer(DoubleArray(size) { initializer(it) }) RealBuffer(DoubleArray(size) { initializer(it) })
/** /**
@ -90,7 +90,7 @@ class RealNDField(override val shape: IntArray) :
/** /**
* Fast element production using function inlining * Fast element production using function inlining
*/ */
inline fun BufferedNDField<Double, RealField>.produceInline(crossinline initializer: RealField.(Int) -> Double): RealNDElement { public inline fun BufferedNDField<Double, RealField>.produceInline(crossinline initializer: RealField.(Int) -> Double): RealNDElement {
val array = DoubleArray(strides.linearSize) { offset -> RealField.initializer(offset) } val array = DoubleArray(strides.linearSize) { offset -> RealField.initializer(offset) }
return BufferedNDFieldElement(this, RealBuffer(array)) return BufferedNDFieldElement(this, RealBuffer(array))
} }
@ -98,13 +98,13 @@ inline fun BufferedNDField<Double, RealField>.produceInline(crossinline initiali
/** /**
* Map one [RealNDElement] using function with indices. * Map one [RealNDElement] using function with indices.
*/ */
inline fun RealNDElement.mapIndexed(crossinline transform: RealField.(index: IntArray, Double) -> Double): RealNDElement = public inline fun RealNDElement.mapIndexed(crossinline transform: RealField.(index: IntArray, Double) -> Double): RealNDElement =
context.produceInline { offset -> transform(strides.index(offset), buffer[offset]) } context.produceInline { offset -> transform(strides.index(offset), buffer[offset]) }
/** /**
* Map one [RealNDElement] using function without indices. * Map one [RealNDElement] using function without indices.
*/ */
inline fun RealNDElement.map(crossinline transform: RealField.(Double) -> Double): RealNDElement { public inline fun RealNDElement.map(crossinline transform: RealField.(Double) -> Double): RealNDElement {
val array = DoubleArray(strides.linearSize) { offset -> RealField.transform(buffer[offset]) } val array = DoubleArray(strides.linearSize) { offset -> RealField.transform(buffer[offset]) }
return BufferedNDFieldElement(context, RealBuffer(array)) return BufferedNDFieldElement(context, RealBuffer(array))
} }

View File

@ -8,7 +8,7 @@ import kotlin.contracts.contract
* *
* @property array the underlying array. * @property array the underlying array.
*/ */
inline class ShortBuffer(val array: ShortArray) : MutableBuffer<Short> { public inline class ShortBuffer(public val array: ShortArray) : MutableBuffer<Short> {
override val size: Int get() = array.size override val size: Int get() = array.size
override operator fun get(index: Int): Short = array[index] override operator fun get(index: Int): Short = array[index]
@ -30,7 +30,7 @@ inline class ShortBuffer(val array: ShortArray) : MutableBuffer<Short> {
* The function [init] is called for each array element sequentially starting from the first one. * The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an buffer element given its index. * It should return the value for an buffer element given its index.
*/ */
inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer { public inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer {
contract { callsInPlace(init) } contract { callsInPlace(init) }
return ShortBuffer(ShortArray(size) { init(it) }) return ShortBuffer(ShortArray(size) { init(it) })
} }
@ -38,12 +38,12 @@ inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer {
/** /**
* Returns a new [ShortBuffer] of given elements. * Returns a new [ShortBuffer] of given elements.
*/ */
fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts) public fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts)
/** /**
* Returns a [ShortArray] containing all of the elements of this [MutableBuffer]. * Returns a [ShortArray] containing all of the elements of this [MutableBuffer].
*/ */
val MutableBuffer<out Short>.array: ShortArray public val MutableBuffer<out Short>.array: ShortArray
get() = (if (this is ShortBuffer) array else ShortArray(size) { get(it) }) get() = (if (this is ShortBuffer) array else ShortArray(size) { get(it) })
/** /**
@ -52,4 +52,4 @@ val MutableBuffer<out Short>.array: ShortArray
* @receiver the array. * @receiver the array.
* @return the new buffer. * @return the new buffer.
*/ */
fun ShortArray.asBuffer(): ShortBuffer = ShortBuffer(this) public fun ShortArray.asBuffer(): ShortBuffer = ShortBuffer(this)

View File

@ -2,20 +2,19 @@ package scientifik.kmath.structures
import scientifik.kmath.operations.RingElement import scientifik.kmath.operations.RingElement
import scientifik.kmath.operations.ShortRing import scientifik.kmath.operations.ShortRing
import kotlin.contracts.contract
public typealias ShortNDElement = BufferedNDRingElement<Short, ShortRing>
typealias ShortNDElement = BufferedNDRingElement<Short, ShortRing> public class ShortNDRing(override val shape: IntArray) :
class ShortNDRing(override val shape: IntArray) :
BufferedNDRing<Short, ShortRing> { BufferedNDRing<Short, ShortRing> {
override val strides: Strides = DefaultStrides(shape) override val strides: Strides = DefaultStrides(shape)
override val elementContext: ShortRing get() = ShortRing override val elementContext: ShortRing get() = ShortRing
override val zero: ShortNDElement by lazy { produce { zero } } override val zero: ShortNDElement by lazy { produce { zero } }
override val one: ShortNDElement by lazy { produce { one } } override val one: ShortNDElement by lazy { produce { one } }
inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Short): Buffer<Short> = public inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Short): Buffer<Short> =
ShortBuffer(ShortArray(size) { initializer(it) }) ShortBuffer(ShortArray(size) { initializer(it) })
/** /**
@ -70,7 +69,8 @@ class ShortNDRing(override val shape: IntArray) :
/** /**
* Fast element production using function inlining. * Fast element production using function inlining.
*/ */
inline fun BufferedNDRing<Short, ShortRing>.produceInline(crossinline initializer: ShortRing.(Int) -> Short): ShortNDElement { public inline fun BufferedNDRing<Short, ShortRing>.produceInline(crossinline initializer: ShortRing.(Int) -> Short): ShortNDElement {
contract { callsInPlace(initializer) }
val array = ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) } val array = ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) }
return BufferedNDRingElement(this, ShortBuffer(array)) return BufferedNDRingElement(this, ShortBuffer(array))
} }
@ -78,7 +78,7 @@ inline fun BufferedNDRing<Short, ShortRing>.produceInline(crossinline initialize
/** /**
* Element by element application of any operation on elements to the whole array. * Element by element application of any operation on elements to the whole array.
*/ */
operator fun Function1<Short, Short>.invoke(ndElement: ShortNDElement): ShortNDElement = public operator fun Function1<Short, Short>.invoke(ndElement: ShortNDElement): ShortNDElement =
ndElement.context.produceInline { i -> invoke(ndElement.buffer[i]) } ndElement.context.produceInline { i -> invoke(ndElement.buffer[i]) }
@ -87,11 +87,11 @@ operator fun Function1<Short, Short>.invoke(ndElement: ShortNDElement): ShortNDE
/** /**
* Summation operation for [ShortNDElement] and single element. * Summation operation for [ShortNDElement] and single element.
*/ */
operator fun ShortNDElement.plus(arg: Short): ShortNDElement = public operator fun ShortNDElement.plus(arg: Short): ShortNDElement =
context.produceInline { i -> (buffer[i] + arg).toShort() } context.produceInline { i -> (buffer[i] + arg).toShort() }
/** /**
* Subtraction operation between [ShortNDElement] and single element. * Subtraction operation between [ShortNDElement] and single element.
*/ */
operator fun ShortNDElement.minus(arg: Short): ShortNDElement = public operator fun ShortNDElement.minus(arg: Short): ShortNDElement =
context.produceInline { i -> (buffer[i] - arg).toShort() } context.produceInline { i -> (buffer[i] - arg).toShort() }

View File

@ -3,26 +3,22 @@ package scientifik.kmath.structures
/** /**
* A structure that is guaranteed to be two-dimensional * A structure that is guaranteed to be two-dimensional
*/ */
interface Structure2D<T> : NDStructure<T> { public interface Structure2D<T> : NDStructure<T> {
val rowNum: Int get() = shape[0] public val rowNum: Int get() = shape[0]
val colNum: Int get() = shape[1] public val colNum: Int get() = shape[1]
operator fun get(i: Int, j: Int): T public operator fun get(i: Int, j: Int): T
override operator fun get(index: IntArray): T { override operator fun get(index: IntArray): T {
require(index.size == 2) { "Index dimension mismatch. Expected 2 but found ${index.size}" } require(index.size == 2) { "Index dimension mismatch. Expected 2 but found ${index.size}" }
return get(index[0], index[1]) return get(index[0], index[1])
} }
val rows: Buffer<Buffer<T>> public val rows: Buffer<Buffer<T>>
get() = VirtualBuffer(rowNum) { i -> get() = VirtualBuffer(rowNum) { i -> VirtualBuffer(colNum) { j -> get(i, j) } }
VirtualBuffer(colNum) { j -> get(i, j) }
}
val columns: Buffer<Buffer<T>> public val columns: Buffer<Buffer<T>>
get() = VirtualBuffer(colNum) { j -> get() = VirtualBuffer(colNum) { j -> VirtualBuffer(rowNum) { i -> get(i, j) } }
VirtualBuffer(rowNum) { i -> get(i, j) }
}
override fun elements(): Sequence<Pair<IntArray, T>> = sequence { override fun elements(): Sequence<Pair<IntArray, T>> = sequence {
for (i in (0 until rowNum)) { for (i in (0 until rowNum)) {
@ -32,7 +28,7 @@ interface Structure2D<T> : NDStructure<T> {
} }
} }
companion object public companion object
} }
/** /**
@ -49,10 +45,10 @@ private inline class Structure2DWrapper<T>(val structure: NDStructure<T>) : Stru
/** /**
* Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch * Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch
*/ */
fun <T> NDStructure<T>.as2D(): Structure2D<T> = if (shape.size == 2) { public fun <T> NDStructure<T>.as2D(): Structure2D<T> = if (shape.size == 2) {
Structure2DWrapper(this) Structure2DWrapper(this)
} else { } else {
error("Can't create 2d-structure from ${shape.size}d-structure") error("Can't create 2d-structure from ${shape.size}d-structure")
} }
typealias Matrix<T> = Structure2D<T> public typealias Matrix<T> = Structure2D<T>

View File

@ -7,7 +7,7 @@ import java.math.MathContext
/** /**
* A field over [BigInteger]. * A field over [BigInteger].
*/ */
object JBigIntegerField : Field<BigInteger> { public object JBigIntegerField : Field<BigInteger> {
override val zero: BigInteger override val zero: BigInteger
get() = BigInteger.ZERO get() = BigInteger.ZERO
@ -28,7 +28,7 @@ object JBigIntegerField : Field<BigInteger> {
* *
* @property mathContext the [MathContext] to use. * @property mathContext the [MathContext] to use.
*/ */
abstract class JBigDecimalFieldBase internal constructor(val mathContext: MathContext = MathContext.DECIMAL64) : public abstract class JBigDecimalFieldBase internal constructor(public val mathContext: MathContext = MathContext.DECIMAL64) :
Field<BigDecimal>, Field<BigDecimal>,
PowerOperations<BigDecimal> { PowerOperations<BigDecimal> {
override val zero: BigDecimal override val zero: BigDecimal
@ -54,6 +54,6 @@ abstract class JBigDecimalFieldBase internal constructor(val mathContext: MathCo
/** /**
* A field over [BigDecimal]. * A field over [BigDecimal].
*/ */
class JBigDecimalField(mathContext: MathContext = MathContext.DECIMAL64) : JBigDecimalFieldBase(mathContext) { public class JBigDecimalField(mathContext: MathContext = MathContext.DECIMAL64) : JBigDecimalFieldBase(mathContext) {
companion object : JBigDecimalFieldBase() public companion object : JBigDecimalFieldBase()
} }

View File

@ -1,12 +1,8 @@
plugins { plugins { id("ru.mipt.npm.mpp") }
id("scientifik.mpp")
//id("scientifik.atomic")
}
kotlin.sourceSets { kotlin.sourceSets {
all { all {
with(languageSettings) { with(languageSettings) {
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
useExperimentalAnnotation("kotlinx.coroutines.InternalCoroutinesApi") useExperimentalAnnotation("kotlinx.coroutines.InternalCoroutinesApi")
useExperimentalAnnotation("kotlinx.coroutines.ExperimentalCoroutinesApi") useExperimentalAnnotation("kotlinx.coroutines.ExperimentalCoroutinesApi")
useExperimentalAnnotation("kotlinx.coroutines.FlowPreview") useExperimentalAnnotation("kotlinx.coroutines.FlowPreview")
@ -16,15 +12,7 @@ kotlin.sourceSets {
commonMain { commonMain {
dependencies { dependencies {
api(project(":kmath-core")) api(project(":kmath-core"))
api("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:${Scientifik.coroutinesVersion}") api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}")
} }
} }
jvmMain {
dependencies { api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Scientifik.coroutinesVersion}") }
}
jsMain {
dependencies { api("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:${Scientifik.coroutinesVersion}") }
}
} }

View File

@ -26,31 +26,31 @@ import kotlinx.coroutines.sync.withLock
* A not-necessary-Markov chain of some type * A not-necessary-Markov chain of some type
* @param R - the chain element type * @param R - the chain element type
*/ */
interface Chain<out R> : Flow<R> { public interface Chain<out R> : Flow<R> {
/** /**
* Generate next value, changing state if needed * Generate next value, changing state if needed
*/ */
suspend fun next(): R public suspend fun next(): R
/** /**
* Create a copy of current chain state. Consuming resulting chain does not affect initial chain * Create a copy of current chain state. Consuming resulting chain does not affect initial chain
*/ */
fun fork(): Chain<R> public fun fork(): Chain<R>
override suspend fun collect(collector: FlowCollector<R>): Unit = override suspend fun collect(collector: FlowCollector<R>): Unit =
flow { while (true) emit(next()) }.collect(collector) flow { while (true) emit(next()) }.collect(collector)
companion object public companion object
} }
fun <T> Iterator<T>.asChain(): Chain<T> = SimpleChain { next() } public fun <T> Iterator<T>.asChain(): Chain<T> = SimpleChain { next() }
fun <T> Sequence<T>.asChain(): Chain<T> = iterator().asChain() public fun <T> Sequence<T>.asChain(): Chain<T> = iterator().asChain()
/** /**
* A simple chain of independent tokens * A simple chain of independent tokens
*/ */
class SimpleChain<out R>(private val gen: suspend () -> R) : Chain<R> { public class SimpleChain<out R>(private val gen: suspend () -> R) : Chain<R> {
override suspend fun next(): R = gen() override suspend fun next(): R = gen()
override fun fork(): Chain<R> = this override fun fork(): Chain<R> = this
} }
@ -58,13 +58,13 @@ class SimpleChain<out R>(private val gen: suspend () -> R) : Chain<R> {
/** /**
* A stateless Markov chain * A stateless Markov chain
*/ */
class MarkovChain<out R : Any>(private val seed: suspend () -> R, private val gen: suspend (R) -> R) : Chain<R> { public class MarkovChain<out R : Any>(private val seed: suspend () -> R, private val gen: suspend (R) -> R) : Chain<R> {
private val mutex = Mutex() private val mutex = Mutex()
private var value: R? = null private var value: R? = null
fun value(): R? = value public fun value(): R? = value
override suspend fun next(): R { override suspend fun next(): R {
mutex.withLock { mutex.withLock {
@ -84,7 +84,7 @@ class MarkovChain<out R : Any>(private val seed: suspend () -> R, private val ge
* @param S - the state of the chain * @param S - the state of the chain
* @param forkState - the function to copy current state without modifying it * @param forkState - the function to copy current state without modifying it
*/ */
class StatefulChain<S, out R>( public class StatefulChain<S, out R>(
private val state: S, private val state: S,
private val seed: S.() -> R, private val seed: S.() -> R,
private val forkState: ((S) -> S), private val forkState: ((S) -> S),
@ -94,7 +94,7 @@ class StatefulChain<S, out R>(
private var value: R? = null private var value: R? = null
fun value(): R? = value public fun value(): R? = value
override suspend fun next(): R { override suspend fun next(): R {
mutex.withLock { mutex.withLock {
@ -110,19 +110,17 @@ class StatefulChain<S, out R>(
/** /**
* A chain that repeats the same value * A chain that repeats the same value
*/ */
class ConstantChain<out T>(val value: T) : Chain<T> { public class ConstantChain<out T>(public val value: T) : Chain<T> {
override suspend fun next(): T = value override suspend fun next(): T = value
override fun fork(): Chain<T> { override fun fork(): Chain<T> = this
return this
}
} }
/** /**
* Map the chain result using suspended transformation. Initial chain result can no longer be safely consumed * Map the chain result using suspended transformation. Initial chain result can no longer be safely consumed
* since mapped chain consumes tokens. Accepts regular transformation function * since mapped chain consumes tokens. Accepts regular transformation function
*/ */
fun <T, R> Chain<T>.map(func: suspend (T) -> R): Chain<R> = object : Chain<R> { public fun <T, R> Chain<T>.map(func: suspend (T) -> R): Chain<R> = object : Chain<R> {
override suspend fun next(): R = func(this@map.next()) override suspend fun next(): R = func(this@map.next())
override fun fork(): Chain<R> = this@map.fork().map(func) override fun fork(): Chain<R> = this@map.fork().map(func)
} }
@ -130,7 +128,7 @@ fun <T, R> Chain<T>.map(func: suspend (T) -> R): Chain<R> = object : Chain<R> {
/** /**
* [block] must be a pure function or at least not use external random variables, otherwise fork could be broken * [block] must be a pure function or at least not use external random variables, otherwise fork could be broken
*/ */
fun <T> Chain<T>.filter(block: (T) -> Boolean): Chain<T> = object : Chain<T> { public fun <T> Chain<T>.filter(block: (T) -> Boolean): Chain<T> = object : Chain<T> {
override suspend fun next(): T { override suspend fun next(): T {
var next: T var next: T
@ -146,12 +144,12 @@ fun <T> Chain<T>.filter(block: (T) -> Boolean): Chain<T> = object : Chain<T> {
/** /**
* Map the whole chain * Map the whole chain
*/ */
fun <T, R> Chain<T>.collect(mapper: suspend (Chain<T>) -> R): Chain<R> = object : Chain<R> { public fun <T, R> Chain<T>.collect(mapper: suspend (Chain<T>) -> R): Chain<R> = object : Chain<R> {
override suspend fun next(): R = mapper(this@collect) override suspend fun next(): R = mapper(this@collect)
override fun fork(): Chain<R> = this@collect.fork().collect(mapper) override fun fork(): Chain<R> = this@collect.fork().collect(mapper)
} }
fun <T, S, R> Chain<T>.collectWithState(state: S, stateFork: (S) -> S, mapper: suspend S.(Chain<T>) -> R): Chain<R> = public fun <T, S, R> Chain<T>.collectWithState(state: S, stateFork: (S) -> S, mapper: suspend S.(Chain<T>) -> R): Chain<R> =
object : Chain<R> { object : Chain<R> {
override suspend fun next(): R = state.mapper(this@collectWithState) override suspend fun next(): R = state.mapper(this@collectWithState)
@ -162,7 +160,7 @@ fun <T, S, R> Chain<T>.collectWithState(state: S, stateFork: (S) -> S, mapper: s
/** /**
* Zip two chains together using given transformation * Zip two chains together using given transformation
*/ */
fun <T, U, R> Chain<T>.zip(other: Chain<U>, block: suspend (T, U) -> R): Chain<R> = object : Chain<R> { public fun <T, U, R> Chain<T>.zip(other: Chain<U>, block: suspend (T, U) -> R): Chain<R> = object : Chain<R> {
override suspend fun next(): R = block(this@zip.next(), other.next()) override suspend fun next(): R = block(this@zip.next(), other.next())
override fun fork(): Chain<R> = this@zip.fork().zip(other.fork(), block) override fun fork(): Chain<R> = this@zip.fork().zip(other.fork(), block)
} }

View File

@ -1,8 +1,6 @@
plugins { plugins { id("ru.mipt.npm.mpp") }
id("scientifik.mpp")
}
description = "A proof of concept module for adding typ-safe dimensions to structures" description = "A proof of concept module for adding type-safe dimensions to structures"
kotlin.sourceSets { kotlin.sourceSets {
commonMain { commonMain {
@ -11,8 +9,8 @@ kotlin.sourceSets {
} }
} }
jvmMain{ jvmMain {
dependencies{ dependencies {
api(kotlin("reflect")) api(kotlin("reflect"))
} }
} }

View File

@ -6,30 +6,28 @@ import kotlin.reflect.KClass
* An abstract class which is not used in runtime. Designates a size of some structure. * An abstract class which is not used in runtime. Designates a size of some structure.
* Could be replaced later by fully inline constructs * Could be replaced later by fully inline constructs
*/ */
interface Dimension { public interface Dimension {
public val dim: UInt
val dim: UInt public companion object
companion object {
}
} }
fun <D : Dimension> KClass<D>.dim(): UInt = Dimension.resolve(this).dim public fun <D : Dimension> KClass<D>.dim(): UInt = Dimension.resolve(this).dim
expect fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D public expect fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D
expect fun Dimension.Companion.of(dim: UInt): Dimension public expect fun Dimension.Companion.of(dim: UInt): Dimension
inline fun <reified D : Dimension> Dimension.Companion.dim(): UInt = D::class.dim() public inline fun <reified D : Dimension> Dimension.Companion.dim(): UInt = D::class.dim()
object D1 : Dimension { public object D1 : Dimension {
override val dim: UInt get() = 1U override val dim: UInt get() = 1U
} }
object D2 : Dimension { public object D2 : Dimension {
override val dim: UInt get() = 2U override val dim: UInt get() = 2U
} }
object D3 : Dimension { public object D3 : Dimension {
override val dim: UInt get() = 3U override val dim: UInt get() = 3U
} }

View File

@ -9,11 +9,11 @@ private val dimensionMap = hashMapOf<UInt, Dimension>(
) )
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
actual fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D { public actual fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D {
return dimensionMap.entries.find { it.value::class == type }?.value as? D ?: error("Can't resolve dimension $type") return dimensionMap.entries.find { it.value::class == type }?.value as? D ?: error("Can't resolve dimension $type")
} }
actual fun Dimension.Companion.of(dim: UInt): Dimension { public actual fun Dimension.Companion.of(dim: UInt): Dimension {
return dimensionMap.getOrPut(dim) { return dimensionMap.getOrPut(dim) {
object : Dimension { object : Dimension {
override val dim: UInt get() = dim override val dim: UInt get() = dim

View File

@ -2,11 +2,11 @@ package scientifik.kmath.dimensions
import kotlin.reflect.KClass import kotlin.reflect.KClass
actual fun <D:Dimension> Dimension.Companion.resolve(type: KClass<D>): D{ public actual fun <D:Dimension> Dimension.Companion.resolve(type: KClass<D>): D{
return type.objectInstance ?: error("No object instance for dimension class") return type.objectInstance ?: error("No object instance for dimension class")
} }
actual fun Dimension.Companion.of(dim: UInt): Dimension{ public actual fun Dimension.Companion.of(dim: UInt): Dimension{
return when(dim){ return when(dim){
1u -> D1 1u -> D1
2u -> D2 2u -> D2

View File

@ -1,6 +1,7 @@
plugins { id("scientifik.mpp") } plugins { id("ru.mipt.npm.mpp") }
kotlin.sourceSets { kotlin.sourceSets.commonMain {
all { languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") } dependencies {
commonMain { dependencies { api(project(":kmath-core")) } } api(project(":kmath-core"))
}
} }

View File

@ -25,20 +25,20 @@ import kotlin.math.pow
* Functions that help create a real (Double) matrix * Functions that help create a real (Double) matrix
*/ */
typealias RealMatrix = Matrix<Double> public typealias RealMatrix = Matrix<Double>
fun realMatrix(rowNum: Int, colNum: Int, initializer: (i: Int, j: Int) -> Double): RealMatrix = public fun realMatrix(rowNum: Int, colNum: Int, initializer: (i: Int, j: Int) -> Double): RealMatrix =
MatrixContext.real.produce(rowNum, colNum, initializer) MatrixContext.real.produce(rowNum, colNum, initializer)
fun Array<DoubleArray>.toMatrix(): RealMatrix { public fun Array<DoubleArray>.toMatrix(): RealMatrix {
return MatrixContext.real.produce(size, this[0].size) { row, col -> this[row][col] } return MatrixContext.real.produce(size, this[0].size) { row, col -> this[row][col] }
} }
fun Sequence<DoubleArray>.toMatrix(): RealMatrix = toList().let { public fun Sequence<DoubleArray>.toMatrix(): RealMatrix = toList().let {
MatrixContext.real.produce(it.size, it[0].size) { row, col -> it[row][col] } MatrixContext.real.produce(it.size, it[0].size) { row, col -> it[row][col] }
} }
fun Matrix<Double>.repeatStackVertical(n: Int): RealMatrix = public fun Matrix<Double>.repeatStackVertical(n: Int): RealMatrix =
VirtualMatrix(rowNum * n, colNum) { row, col -> VirtualMatrix(rowNum * n, colNum) { row, col ->
get(if (row == 0) 0 else row % rowNum, col) get(if (row == 0) 0 else row % rowNum, col)
} }
@ -47,37 +47,37 @@ fun Matrix<Double>.repeatStackVertical(n: Int): RealMatrix =
* Operations for matrix and real number * Operations for matrix and real number
*/ */
operator fun Matrix<Double>.times(double: Double): RealMatrix = public operator fun Matrix<Double>.times(double: Double): RealMatrix =
MatrixContext.real.produce(rowNum, colNum) { row, col -> MatrixContext.real.produce(rowNum, colNum) { row, col ->
this[row, col] * double this[row, col] * double
} }
operator fun Matrix<Double>.plus(double: Double): RealMatrix = public operator fun Matrix<Double>.plus(double: Double): RealMatrix =
MatrixContext.real.produce(rowNum, colNum) { row, col -> MatrixContext.real.produce(rowNum, colNum) { row, col ->
this[row, col] + double this[row, col] + double
} }
operator fun Matrix<Double>.minus(double: Double): RealMatrix = public operator fun Matrix<Double>.minus(double: Double): RealMatrix =
MatrixContext.real.produce(rowNum, colNum) { row, col -> MatrixContext.real.produce(rowNum, colNum) { row, col ->
this[row, col] - double this[row, col] - double
} }
operator fun Matrix<Double>.div(double: Double): RealMatrix = public operator fun Matrix<Double>.div(double: Double): RealMatrix =
MatrixContext.real.produce(rowNum, colNum) { row, col -> MatrixContext.real.produce(rowNum, colNum) { row, col ->
this[row, col] / double this[row, col] / double
} }
operator fun Double.times(matrix: Matrix<Double>): RealMatrix = public operator fun Double.times(matrix: Matrix<Double>): RealMatrix =
MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { row, col -> MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { row, col ->
this * matrix[row, col] this * matrix[row, col]
} }
operator fun Double.plus(matrix: Matrix<Double>): RealMatrix = public operator fun Double.plus(matrix: Matrix<Double>): RealMatrix =
MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { row, col -> MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { row, col ->
this + matrix[row, col] this + matrix[row, col]
} }
operator fun Double.minus(matrix: Matrix<Double>): RealMatrix = public operator fun Double.minus(matrix: Matrix<Double>): RealMatrix =
MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { row, col -> MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { row, col ->
this - matrix[row, col] this - matrix[row, col]
} }
@ -91,11 +91,11 @@ operator fun Double.minus(matrix: Matrix<Double>): RealMatrix =
* Per-element (!) square and power operations * Per-element (!) square and power operations
*/ */
fun Matrix<Double>.square(): RealMatrix = MatrixContext.real.produce(rowNum, colNum) { row, col -> public fun Matrix<Double>.square(): RealMatrix = MatrixContext.real.produce(rowNum, colNum) { row, col ->
this[row, col].pow(2) this[row, col].pow(2)
} }
fun Matrix<Double>.pow(n: Int): RealMatrix = MatrixContext.real.produce(rowNum, colNum) { i, j -> public fun Matrix<Double>.pow(n: Int): RealMatrix = MatrixContext.real.produce(rowNum, colNum) { i, j ->
this[i, j].pow(n) this[i, j].pow(n)
} }
@ -103,24 +103,20 @@ fun Matrix<Double>.pow(n: Int): RealMatrix = MatrixContext.real.produce(rowNum,
* Operations on two matrices (per-element!) * Operations on two matrices (per-element!)
*/ */
operator fun Matrix<Double>.times(other: Matrix<Double>): RealMatrix = public operator fun Matrix<Double>.times(other: Matrix<Double>): RealMatrix =
MatrixContext.real.produce(rowNum, colNum) { row, col -> MatrixContext.real.produce(rowNum, colNum) { row, col -> this[row, col] * other[row, col] }
this[row, col] * other[row, col]
}
operator fun Matrix<Double>.plus(other: Matrix<Double>): RealMatrix = public operator fun Matrix<Double>.plus(other: Matrix<Double>): RealMatrix =
MatrixContext.real.add(this, other) MatrixContext.real.add(this, other)
operator fun Matrix<Double>.minus(other: Matrix<Double>): RealMatrix = public operator fun Matrix<Double>.minus(other: Matrix<Double>): RealMatrix =
MatrixContext.real.produce(rowNum, colNum) { row, col -> MatrixContext.real.produce(rowNum, colNum) { row, col -> this[row, col] - other[row, col] }
this[row, col] - other[row, col]
}
/* /*
* Operations on columns * Operations on columns
*/ */
inline fun Matrix<Double>.appendColumn(crossinline mapper: (Buffer<Double>) -> Double): Matrix<Double> { public inline fun Matrix<Double>.appendColumn(crossinline mapper: (Buffer<Double>) -> Double): Matrix<Double> {
contract { callsInPlace(mapper) } contract { callsInPlace(mapper) }
return MatrixContext.real.produce(rowNum, colNum + 1) { row, col -> return MatrixContext.real.produce(rowNum, colNum + 1) { row, col ->
@ -131,28 +127,28 @@ inline fun Matrix<Double>.appendColumn(crossinline mapper: (Buffer<Double>) -> D
} }
} }
fun Matrix<Double>.extractColumns(columnRange: IntRange): RealMatrix = public fun Matrix<Double>.extractColumns(columnRange: IntRange): RealMatrix =
MatrixContext.real.produce(rowNum, columnRange.count()) { row, col -> MatrixContext.real.produce(rowNum, columnRange.count()) { row, col ->
this[row, columnRange.first + col] this[row, columnRange.first + col]
} }
fun Matrix<Double>.extractColumn(columnIndex: Int): RealMatrix = public fun Matrix<Double>.extractColumn(columnIndex: Int): RealMatrix =
extractColumns(columnIndex..columnIndex) extractColumns(columnIndex..columnIndex)
fun Matrix<Double>.sumByColumn(): RealBuffer = RealBuffer(colNum) { j -> public fun Matrix<Double>.sumByColumn(): RealBuffer = RealBuffer(colNum) { j ->
val column = columns[j] val column = columns[j]
elementContext { sum(column.asIterable()) } elementContext { sum(column.asIterable()) }
} }
fun Matrix<Double>.minByColumn(): RealBuffer = RealBuffer(colNum) { j -> public fun Matrix<Double>.minByColumn(): RealBuffer = RealBuffer(colNum) { j ->
columns[j].asIterable().min() ?: error("Cannot produce min on empty column") columns[j].asIterable().min() ?: error("Cannot produce min on empty column")
} }
fun Matrix<Double>.maxByColumn(): RealBuffer = RealBuffer(colNum) { j -> public fun Matrix<Double>.maxByColumn(): RealBuffer = RealBuffer(colNum) { j ->
columns[j].asIterable().max() ?: error("Cannot produce min on empty column") columns[j].asIterable().max() ?: error("Cannot produce min on empty column")
} }
fun Matrix<Double>.averageByColumn(): RealBuffer = RealBuffer(colNum) { j -> public fun Matrix<Double>.averageByColumn(): RealBuffer = RealBuffer(colNum) { j ->
columns[j].asIterable().average() columns[j].asIterable().average()
} }
@ -160,7 +156,7 @@ fun Matrix<Double>.averageByColumn(): RealBuffer = RealBuffer(colNum) { j ->
* Operations processing all elements * Operations processing all elements
*/ */
fun Matrix<Double>.sum(): Double = elements().map { (_, value) -> value }.sum() public fun Matrix<Double>.sum(): Double = elements().map { (_, value) -> value }.sum()
fun Matrix<Double>.min(): Double? = elements().map { (_, value) -> value }.min() public fun Matrix<Double>.min(): Double? = elements().map { (_, value) -> value }.min()
fun Matrix<Double>.max(): Double? = elements().map { (_, value) -> value }.max() public fun Matrix<Double>.max(): Double? = elements().map { (_, value) -> value }.max()
fun Matrix<Double>.average(): Double = elements().map { (_, value) -> value }.average() public fun Matrix<Double>.average(): Double = elements().map { (_, value) -> value }.average()

View File

@ -1,6 +1,7 @@
plugins { id("scientifik.mpp") } plugins { id("ru.mipt.npm.mpp") }
kotlin.sourceSets { kotlin.sourceSets.commonMain {
all { languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") } dependencies {
commonMain { dependencies { api(project(":kmath-core")) } } api(project(":kmath-core"))
}
} }

View File

@ -2,17 +2,17 @@ package scientifik.kmath.functions
import scientifik.kmath.operations.Ring import scientifik.kmath.operations.Ring
interface Piecewise<T, R> { public fun interface Piecewise<T, R> {
fun findPiece(arg: T): R? public fun findPiece(arg: T): R?
} }
interface PiecewisePolynomial<T : Any> : public fun interface PiecewisePolynomial<T : Any> :
Piecewise<T, Polynomial<T>> Piecewise<T, Polynomial<T>>
/** /**
* Ordered list of pieces in piecewise function * Ordered list of pieces in piecewise function
*/ */
class OrderedPiecewisePolynomial<T : Comparable<T>>(delimeter: T) : public class OrderedPiecewisePolynomial<T : Comparable<T>>(delimeter: T) :
PiecewisePolynomial<T> { PiecewisePolynomial<T> {
private val delimiters: ArrayList<T> = arrayListOf(delimeter) private val delimiters: ArrayList<T> = arrayListOf(delimeter)
@ -22,13 +22,13 @@ class OrderedPiecewisePolynomial<T : Comparable<T>>(delimeter: T) :
* Dynamically add a piece to the "right" side (beyond maximum argument value of previous piece) * Dynamically add a piece to the "right" side (beyond maximum argument value of previous piece)
* @param right new rightmost position. If is less then current rightmost position, a error is thrown. * @param right new rightmost position. If is less then current rightmost position, a error is thrown.
*/ */
fun putRight(right: T, piece: Polynomial<T>) { public fun putRight(right: T, piece: Polynomial<T>) {
require(right > delimiters.last()) { "New delimiter should be to the right of old one" } require(right > delimiters.last()) { "New delimiter should be to the right of old one" }
delimiters.add(right) delimiters.add(right)
pieces.add(piece) pieces.add(piece)
} }
fun putLeft(left: T, piece: Polynomial<T>) { public fun putLeft(left: T, piece: Polynomial<T>) {
require(left < delimiters.first()) { "New delimiter should be to the left of old one" } require(left < delimiters.first()) { "New delimiter should be to the left of old one" }
delimiters.add(0, left) delimiters.add(0, left)
pieces.add(0, piece) pieces.add(0, piece)
@ -51,7 +51,7 @@ class OrderedPiecewisePolynomial<T : Comparable<T>>(delimeter: T) :
/** /**
* Return a value of polynomial function with given [ring] an given [arg] or null if argument is outside of piecewise definition. * Return a value of polynomial function with given [ring] an given [arg] or null if argument is outside of piecewise definition.
*/ */
fun <T : Comparable<T>, C : Ring<T>> PiecewisePolynomial<T>.value(ring: C, arg: T): T? = public fun <T : Comparable<T>, C : Ring<T>> PiecewisePolynomial<T>.value(ring: C, arg: T): T? =
findPiece(arg)?.value(ring, arg) findPiece(arg)?.value(ring, arg)
fun <T : Comparable<T>, C : Ring<T>> PiecewisePolynomial<T>.asFunction(ring: C): (T) -> T? = { value(ring, it) } public fun <T : Comparable<T>, C : Ring<T>> PiecewisePolynomial<T>.asFunction(ring: C): (T) -> T? = { value(ring, it) }

View File

@ -3,7 +3,6 @@ package scientifik.kmath.functions
import scientifik.kmath.operations.Ring import scientifik.kmath.operations.Ring
import scientifik.kmath.operations.Space import scientifik.kmath.operations.Space
import scientifik.kmath.operations.invoke import scientifik.kmath.operations.invoke
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.math.max import kotlin.math.max
@ -13,14 +12,14 @@ import kotlin.math.pow
* Polynomial coefficients without fixation on specific context they are applied to * Polynomial coefficients without fixation on specific context they are applied to
* @param coefficients constant is the leftmost coefficient * @param coefficients constant is the leftmost coefficient
*/ */
inline class Polynomial<T : Any>(val coefficients: List<T>) { public inline class Polynomial<T : Any>(public val coefficients: List<T>) {
constructor(vararg coefficients: T) : this(coefficients.toList()) public constructor(vararg coefficients: T) : this(coefficients.toList())
} }
fun Polynomial<Double>.value(): Double = public fun Polynomial<Double>.value(): Double =
coefficients.reduceIndexed { index: Int, acc: Double, d: Double -> acc + d.pow(index) } coefficients.reduceIndexed { index: Int, acc: Double, d: Double -> acc + d.pow(index) }
fun <T : Any, C : Ring<T>> Polynomial<T>.value(ring: C, arg: T): T = ring { public fun <T : Any, C : Ring<T>> Polynomial<T>.value(ring: C, arg: T): T = ring {
if (coefficients.isEmpty()) return@ring zero if (coefficients.isEmpty()) return@ring zero
var res = coefficients.first() var res = coefficients.first()
var powerArg = arg var powerArg = arg
@ -37,20 +36,19 @@ fun <T : Any, C : Ring<T>> Polynomial<T>.value(ring: C, arg: T): T = ring {
/** /**
* Represent a polynomial as a context-dependent function * Represent a polynomial as a context-dependent function
*/ */
fun <T : Any, C : Ring<T>> Polynomial<T>.asMathFunction(): MathFunction<T, out C, T> = object : public fun <T : Any, C : Ring<T>> Polynomial<T>.asMathFunction(): MathFunction<T, out C, T> =
MathFunction<T, C, T> { MathFunction { arg -> value(this, arg) }
override operator fun C.invoke(arg: T): T = value(this, arg)
}
/** /**
* Represent the polynomial as a regular context-less function * Represent the polynomial as a regular context-less function
*/ */
fun <T : Any, C : Ring<T>> Polynomial<T>.asFunction(ring: C): (T) -> T = { value(ring, it) } public fun <T : Any, C : Ring<T>> Polynomial<T>.asFunction(ring: C): (T) -> T = { value(ring, it) }
/** /**
* An algebra for polynomials * An algebra for polynomials
*/ */
class PolynomialSpace<T : Any, C : Ring<T>>(val ring: C) : Space<Polynomial<T>> { public class PolynomialSpace<T : Any, C : Ring<T>>(public val ring: C) : Space<Polynomial<T>> {
override val zero: Polynomial<T> = Polynomial(emptyList())
override fun add(a: Polynomial<T>, b: Polynomial<T>): Polynomial<T> { override fun add(a: Polynomial<T>, b: Polynomial<T>): Polynomial<T> {
val dim = max(a.coefficients.size, b.coefficients.size) val dim = max(a.coefficients.size, b.coefficients.size)
@ -65,13 +63,10 @@ class PolynomialSpace<T : Any, C : Ring<T>>(val ring: C) : Space<Polynomial<T>>
override fun multiply(a: Polynomial<T>, k: Number): Polynomial<T> = override fun multiply(a: Polynomial<T>, k: Number): Polynomial<T> =
ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * k }) } ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * k }) }
override val zero: Polynomial<T> = public operator fun Polynomial<T>.invoke(arg: T): T = value(ring, arg)
Polynomial(emptyList())
operator fun Polynomial<T>.invoke(arg: T): T = value(ring, arg)
} }
inline fun <T : Any, C : Ring<T>, R> C.polynomial(block: PolynomialSpace<T, C>.() -> R): R { public inline fun <T : Any, C : Ring<T>, R> C.polynomial(block: PolynomialSpace<T, C>.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return PolynomialSpace(this).block() return PolynomialSpace(this).block()
} }

View File

@ -9,25 +9,25 @@ import scientifik.kmath.operations.RealField
* @param C source algebra constraint * @param C source algebra constraint
* @param R result type * @param R result type
*/ */
interface MathFunction<T, C : Algebra<T>, R> { public fun interface MathFunction<T, C : Algebra<T>, R> {
operator fun C.invoke(arg: T): R public operator fun C.invoke(arg: T): R
} }
fun <R> MathFunction<Double, RealField, R>.invoke(arg: Double): R = RealField.invoke(arg) public fun <R> MathFunction<Double, RealField, R>.invoke(arg: Double): R = RealField.invoke(arg)
/** /**
* A suspendable function defined in algebraic context * A suspendable function defined in algebraic context
*/ */
interface SuspendableMathFunction<T, C : Algebra<T>, R> { // TODO make fun interface, when the new JVM IR is enabled
suspend operator fun C.invoke(arg: T): R public interface SuspendableMathFunction<T, C : Algebra<T>, R> {
public suspend operator fun C.invoke(arg: T): R
} }
suspend fun <R> SuspendableMathFunction<Double, RealField, R>.invoke(arg: Double) = RealField.invoke(arg) public suspend fun <R> SuspendableMathFunction<Double, RealField, R>.invoke(arg: Double) = RealField.invoke(arg)
/** /**
* A parametric function with parameter * A parametric function with parameter
*/ */
interface ParametricFunction<T, P, C : Algebra<T>> { public fun interface ParametricFunction<T, P, C : Algebra<T>> {
operator fun C.invoke(arg: T, parameter: P): T public operator fun C.invoke(arg: T, parameter: P): T
} }

View File

@ -6,16 +6,16 @@ import scientifik.kmath.operations.Ring
import scientifik.kmath.structures.Buffer import scientifik.kmath.structures.Buffer
import scientifik.kmath.structures.asBuffer import scientifik.kmath.structures.asBuffer
interface Interpolator<X, Y> { public fun interface Interpolator<X, Y> {
fun interpolate(points: XYPointSet<X, Y>): (X) -> Y public fun interpolate(points: XYPointSet<X, Y>): (X) -> Y
} }
interface PolynomialInterpolator<T : Comparable<T>> : Interpolator<T, T> { public interface PolynomialInterpolator<T : Comparable<T>> : Interpolator<T, T> {
val algebra: Ring<T> public val algebra: Ring<T>
fun getDefaultValue(): T = error("Out of bounds") public fun getDefaultValue(): T = error("Out of bounds")
fun interpolatePolynomials(points: XYPointSet<T, T>): PiecewisePolynomial<T> public fun interpolatePolynomials(points: XYPointSet<T, T>): PiecewisePolynomial<T>
override fun interpolate(points: XYPointSet<T, T>): (T) -> T = { x -> override fun interpolate(points: XYPointSet<T, T>): (T) -> T = { x ->
interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue()

View File

@ -9,7 +9,7 @@ import scientifik.kmath.operations.invoke
/** /**
* Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java
*/ */
class LinearInterpolator<T : Comparable<T>>(override val algebra: Field<T>) : PolynomialInterpolator<T> { public class LinearInterpolator<T : Comparable<T>>(override val algebra: Field<T>) : PolynomialInterpolator<T> {
override fun interpolatePolynomials(points: XYPointSet<T, T>): PiecewisePolynomial<T> = algebra { override fun interpolatePolynomials(points: XYPointSet<T, T>): PiecewisePolynomial<T> = algebra {
require(points.size > 0) { "Point array should not be empty" } require(points.size > 0) { "Point array should not be empty" }
insureSorted(points) insureSorted(points)

View File

@ -11,9 +11,9 @@ import scientifik.kmath.structures.MutableBufferFactory
* Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type specific ones. * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type specific ones.
* Based on https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java * Based on https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java
*/ */
class SplineInterpolator<T : Comparable<T>>( public class SplineInterpolator<T : Comparable<T>>(
override val algebra: Field<T>, override val algebra: Field<T>,
val bufferFactory: MutableBufferFactory<T> public val bufferFactory: MutableBufferFactory<T>
) : PolynomialInterpolator<T> { ) : PolynomialInterpolator<T> {
//TODO possibly optimize zeroed buffers //TODO possibly optimize zeroed buffers

View File

@ -3,21 +3,21 @@ package scientifik.kmath.interpolation
import scientifik.kmath.structures.Buffer import scientifik.kmath.structures.Buffer
import scientifik.kmath.structures.Structure2D import scientifik.kmath.structures.Structure2D
interface XYPointSet<X, Y> { public interface XYPointSet<X, Y> {
val size: Int public val size: Int
val x: Buffer<X> public val x: Buffer<X>
val y: Buffer<Y> public val y: Buffer<Y>
} }
interface XYZPointSet<X, Y, Z> : XYPointSet<X, Y> { public interface XYZPointSet<X, Y, Z> : XYPointSet<X, Y> {
val z: Buffer<Z> public val z: Buffer<Z>
} }
internal fun <T : Comparable<T>> insureSorted(points: XYPointSet<T, *>) { internal fun <T : Comparable<T>> insureSorted(points: XYPointSet<T, *>) {
for (i in 0 until points.size - 1) require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" } for (i in 0 until points.size - 1) require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" }
} }
class NDStructureColumn<T>(val structure: Structure2D<T>, val column: Int) : Buffer<T> { public class NDStructureColumn<T>(public val structure: Structure2D<T>, public val column: Int) : Buffer<T> {
init { init {
require(column < structure.colNum) { "Column index is outside of structure column range" } require(column < structure.colNum) { "Column index is outside of structure column range" }
} }
@ -33,7 +33,7 @@ class NDStructureColumn<T>(val structure: Structure2D<T>, val column: Int) : Buf
}.iterator() }.iterator()
} }
class BufferXYPointSet<X, Y>(override val x: Buffer<X>, override val y: Buffer<Y>) : XYPointSet<X, Y> { public class BufferXYPointSet<X, Y>(override val x: Buffer<X>, override val y: Buffer<Y>) : XYPointSet<X, Y> {
init { init {
require(x.size == y.size) { "Sizes of x and y buffers should be the same" } require(x.size == y.size) { "Sizes of x and y buffers should be the same" }
} }
@ -42,8 +42,9 @@ class BufferXYPointSet<X, Y>(override val x: Buffer<X>, override val y: Buffer<Y
get() = x.size get() = x.size
} }
fun <T> Structure2D<T>.asXYPointSet(): XYPointSet<T, T> { public fun <T> Structure2D<T>.asXYPointSet(): XYPointSet<T, T> {
require(shape[1] == 2) { "Structure second dimension should be of size 2" } require(shape[1] == 2) { "Structure second dimension should be of size 2" }
return object : XYPointSet<T, T> { return object : XYPointSet<T, T> {
override val size: Int get() = this@asXYPointSet.shape[0] override val size: Int get() = this@asXYPointSet.shape[0]
override val x: Buffer<T> get() = NDStructureColumn(this@asXYPointSet, 0) override val x: Buffer<T> get() = NDStructureColumn(this@asXYPointSet, 0)

View File

@ -6,7 +6,6 @@ import scientifik.kmath.operations.RealField
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class LinearInterpolatorTest { class LinearInterpolatorTest {
@Test @Test
fun testInterpolation() { fun testInterpolation() {

View File

@ -1,6 +1,4 @@
plugins { plugins { id("ru.mipt.npm.mpp") }
id("scientifik.mpp")
}
kotlin.sourceSets.commonMain { kotlin.sourceSets.commonMain {
dependencies { dependencies {

View File

@ -1,6 +1,4 @@
plugins { plugins { id("ru.mipt.npm.mpp") }
id("scientifik.mpp")
}
kotlin.sourceSets.commonMain { kotlin.sourceSets.commonMain {
dependencies { dependencies {

View File

@ -1,10 +1,6 @@
plugins { plugins { id("ru.mipt.npm.mpp") }
id("scientifik.mpp")
}
repositories { repositories.maven("http://dl.bintray.com/kyonifer/maven")
maven("http://dl.bintray.com/kyonifer/maven")
}
kotlin.sourceSets { kotlin.sourceSets {
commonMain { commonMain {
@ -13,16 +9,19 @@ kotlin.sourceSets {
api("com.kyonifer:koma-core-api-common:0.12") api("com.kyonifer:koma-core-api-common:0.12")
} }
} }
jvmMain { jvmMain {
dependencies { dependencies {
api("com.kyonifer:koma-core-api-jvm:0.12") api("com.kyonifer:koma-core-api-jvm:0.12")
} }
} }
jvmTest { jvmTest {
dependencies { dependencies {
implementation("com.kyonifer:koma-core-ejml:0.12") implementation("com.kyonifer:koma-core-ejml:0.12")
} }
} }
jsMain { jsMain {
dependencies { dependencies {
api("com.kyonifer:koma-core-api-js:0.12") api("com.kyonifer:koma-core-api-js:0.12")

View File

@ -1,2 +1 @@
plugins { id("scientifik.mpp") } plugins { id("ru.mipt.npm.mpp") }
kotlin.sourceSets.all { languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") }

View File

@ -6,84 +6,84 @@ import kotlin.contracts.contract
/** /**
* Represents a display of certain memory structure. * Represents a display of certain memory structure.
*/ */
interface Memory { public interface Memory {
/** /**
* The length of this memory in bytes. * The length of this memory in bytes.
*/ */
val size: Int public val size: Int
/** /**
* Get a projection of this memory (it reflects the changes in the parent memory block). * Get a projection of this memory (it reflects the changes in the parent memory block).
*/ */
fun view(offset: Int, length: Int): Memory public fun view(offset: Int, length: Int): Memory
/** /**
* Creates an independent copy of this memory. * Creates an independent copy of this memory.
*/ */
fun copy(): Memory public fun copy(): Memory
/** /**
* Gets or creates a reader of this memory. * Gets or creates a reader of this memory.
*/ */
fun reader(): MemoryReader public fun reader(): MemoryReader
/** /**
* Gets or creates a writer of this memory. * Gets or creates a writer of this memory.
*/ */
fun writer(): MemoryWriter public fun writer(): MemoryWriter
companion object public companion object
} }
/** /**
* The interface to read primitive types in this memory. * The interface to read primitive types in this memory.
*/ */
interface MemoryReader { public interface MemoryReader {
/** /**
* The underlying memory. * The underlying memory.
*/ */
val memory: Memory public val memory: Memory
/** /**
* Reads [Double] at certain [offset]. * Reads [Double] at certain [offset].
*/ */
fun readDouble(offset: Int): Double public fun readDouble(offset: Int): Double
/** /**
* Reads [Float] at certain [offset]. * Reads [Float] at certain [offset].
*/ */
fun readFloat(offset: Int): Float public fun readFloat(offset: Int): Float
/** /**
* Reads [Byte] at certain [offset]. * Reads [Byte] at certain [offset].
*/ */
fun readByte(offset: Int): Byte public fun readByte(offset: Int): Byte
/** /**
* Reads [Short] at certain [offset]. * Reads [Short] at certain [offset].
*/ */
fun readShort(offset: Int): Short public fun readShort(offset: Int): Short
/** /**
* Reads [Int] at certain [offset]. * Reads [Int] at certain [offset].
*/ */
fun readInt(offset: Int): Int public fun readInt(offset: Int): Int
/** /**
* Reads [Long] at certain [offset]. * Reads [Long] at certain [offset].
*/ */
fun readLong(offset: Int): Long public fun readLong(offset: Int): Long
/** /**
* Disposes this reader if needed. * Disposes this reader if needed.
*/ */
fun release() public fun release()
} }
/** /**
* Uses the memory for read then releases the reader. * Uses the memory for read then releases the reader.
*/ */
inline fun <R> Memory.read(block: MemoryReader.() -> R): R { public inline fun <R> Memory.read(block: MemoryReader.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
val reader = reader() val reader = reader()
val result = reader.block() val result = reader.block()
@ -94,52 +94,52 @@ inline fun <R> Memory.read(block: MemoryReader.() -> R): R {
/** /**
* The interface to write primitive types into this memory. * The interface to write primitive types into this memory.
*/ */
interface MemoryWriter { public interface MemoryWriter {
/** /**
* The underlying memory. * The underlying memory.
*/ */
val memory: Memory public val memory: Memory
/** /**
* Writes [Double] at certain [offset]. * Writes [Double] at certain [offset].
*/ */
fun writeDouble(offset: Int, value: Double) public fun writeDouble(offset: Int, value: Double)
/** /**
* Writes [Float] at certain [offset]. * Writes [Float] at certain [offset].
*/ */
fun writeFloat(offset: Int, value: Float) public fun writeFloat(offset: Int, value: Float)
/** /**
* Writes [Byte] at certain [offset]. * Writes [Byte] at certain [offset].
*/ */
fun writeByte(offset: Int, value: Byte) public fun writeByte(offset: Int, value: Byte)
/** /**
* Writes [Short] at certain [offset]. * Writes [Short] at certain [offset].
*/ */
fun writeShort(offset: Int, value: Short) public fun writeShort(offset: Int, value: Short)
/** /**
* Writes [Int] at certain [offset]. * Writes [Int] at certain [offset].
*/ */
fun writeInt(offset: Int, value: Int) public fun writeInt(offset: Int, value: Int)
/** /**
* Writes [Long] at certain [offset]. * Writes [Long] at certain [offset].
*/ */
fun writeLong(offset: Int, value: Long) public fun writeLong(offset: Int, value: Long)
/** /**
* Disposes this writer if needed. * Disposes this writer if needed.
*/ */
fun release() public fun release()
} }
/** /**
* Uses the memory for write then releases the writer. * Uses the memory for write then releases the writer.
*/ */
inline fun Memory.write(block: MemoryWriter.() -> Unit) { public inline fun Memory.write(block: MemoryWriter.() -> Unit) {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
writer().apply(block).release() writer().apply(block).release()
} }
@ -147,10 +147,10 @@ inline fun Memory.write(block: MemoryWriter.() -> Unit) {
/** /**
* Allocates the most effective platform-specific memory. * Allocates the most effective platform-specific memory.
*/ */
expect fun Memory.Companion.allocate(length: Int): Memory public expect fun Memory.Companion.allocate(length: Int): Memory
/** /**
* Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied
* and could be mutated independently from the resulting [Memory]. * and could be mutated independently from the resulting [Memory].
*/ */
expect fun Memory.Companion.wrap(array: ByteArray): Memory public expect fun Memory.Companion.wrap(array: ByteArray): Memory

View File

@ -5,45 +5,45 @@ package scientifik.memory
* *
* @param T the type of object this spec manages. * @param T the type of object this spec manages.
*/ */
interface MemorySpec<T : Any> { public interface MemorySpec<T : Any> {
/** /**
* Size of [T] in bytes after serialization. * Size of [T] in bytes after serialization.
*/ */
val objectSize: Int public val objectSize: Int
/** /**
* Reads the object starting from [offset]. * Reads the object starting from [offset].
*/ */
fun MemoryReader.read(offset: Int): T public fun MemoryReader.read(offset: Int): T
// TODO consider thread safety // TODO consider thread safety
/** /**
* Writes the object [value] starting from [offset]. * Writes the object [value] starting from [offset].
*/ */
fun MemoryWriter.write(offset: Int, value: T) public fun MemoryWriter.write(offset: Int, value: T)
} }
/** /**
* Reads the object with [spec] starting from [offset]. * Reads the object with [spec] starting from [offset].
*/ */
fun <T : Any> MemoryReader.read(spec: MemorySpec<T>, offset: Int): T = with(spec) { read(offset) } public fun <T : Any> MemoryReader.read(spec: MemorySpec<T>, offset: Int): T = with(spec) { read(offset) }
/** /**
* Writes the object [value] with [spec] starting from [offset]. * Writes the object [value] with [spec] starting from [offset].
*/ */
fun <T : Any> MemoryWriter.write(spec: MemorySpec<T>, offset: Int, value: T): Unit = with(spec) { write(offset, value) } public fun <T : Any> MemoryWriter.write(spec: MemorySpec<T>, offset: Int, value: T): Unit = with(spec) { write(offset, value) }
/** /**
* Reads array of [size] objects mapped by [spec] at certain [offset]. * Reads array of [size] objects mapped by [spec] at certain [offset].
*/ */
inline fun <reified T : Any> MemoryReader.readArray(spec: MemorySpec<T>, offset: Int, size: Int): Array<T> = public inline fun <reified T : Any> MemoryReader.readArray(spec: MemorySpec<T>, offset: Int, size: Int): Array<T> =
Array(size) { i -> with(spec) { read(offset + i * objectSize) } } Array(size) { i -> with(spec) { read(offset + i * objectSize) } }
/** /**
* Writes [array] of objects mapped by [spec] at certain [offset]. * Writes [array] of objects mapped by [spec] at certain [offset].
*/ */
fun <T : Any> MemoryWriter.writeArray(spec: MemorySpec<T>, offset: Int, array: Array<T>): Unit = public fun <T : Any> MemoryWriter.writeArray(spec: MemorySpec<T>, offset: Int, array: Array<T>): Unit =
with(spec) { array.indices.forEach { i -> write(offset + i * objectSize, array[i]) } } with(spec) { array.indices.forEach { i -> write(offset + i * objectSize, array[i]) } }
// TODO It is possible to add elastic MemorySpec with unknown object size // TODO It is possible to add elastic MemorySpec with unknown object size

View File

@ -83,7 +83,7 @@ private class DataViewMemory(val view: DataView) : Memory {
/** /**
* Allocates memory based on a [DataView]. * Allocates memory based on a [DataView].
*/ */
actual fun Memory.Companion.allocate(length: Int): Memory { public actual fun Memory.Companion.allocate(length: Int): Memory {
val buffer = ArrayBuffer(length) val buffer = ArrayBuffer(length)
return DataViewMemory(DataView(buffer, 0, length)) return DataViewMemory(DataView(buffer, 0, length))
} }
@ -92,7 +92,7 @@ actual fun Memory.Companion.allocate(length: Int): Memory {
* Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied
* and could be mutated independently from the resulting [Memory]. * and could be mutated independently from the resulting [Memory].
*/ */
actual fun Memory.Companion.wrap(array: ByteArray): Memory { public actual fun Memory.Companion.wrap(array: ByteArray): Memory {
@Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array @Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array
return DataViewMemory(DataView(int8Array.buffer, int8Array.byteOffset, int8Array.length)) return DataViewMemory(DataView(int8Array.buffer, int8Array.byteOffset, int8Array.length))
} }

View File

@ -94,14 +94,14 @@ internal class ByteBufferMemory(
/** /**
* Allocates memory based on a [ByteBuffer]. * Allocates memory based on a [ByteBuffer].
*/ */
actual fun Memory.Companion.allocate(length: Int): Memory = public actual fun Memory.Companion.allocate(length: Int): Memory =
ByteBufferMemory(checkNotNull(ByteBuffer.allocate(length))) ByteBufferMemory(checkNotNull(ByteBuffer.allocate(length)))
/** /**
* Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied
* and could be mutated independently from the resulting [Memory]. * and could be mutated independently from the resulting [Memory].
*/ */
actual fun Memory.Companion.wrap(array: ByteArray): Memory = ByteBufferMemory(checkNotNull(ByteBuffer.wrap(array))) public actual fun Memory.Companion.wrap(array: ByteArray): Memory = ByteBufferMemory(checkNotNull(ByteBuffer.wrap(array)))
/** /**
* Wraps this [ByteBuffer] to [Memory] object. * Wraps this [ByteBuffer] to [Memory] object.
@ -111,14 +111,14 @@ actual fun Memory.Companion.wrap(array: ByteArray): Memory = ByteBufferMemory(ch
* @param size the size of memory to map. * @param size the size of memory to map.
* @return the [Memory] object. * @return the [Memory] object.
*/ */
fun ByteBuffer.asMemory(startOffset: Int = 0, size: Int = limit()): Memory = public fun ByteBuffer.asMemory(startOffset: Int = 0, size: Int = limit()): Memory =
ByteBufferMemory(this, startOffset, size) ByteBufferMemory(this, startOffset, size)
/** /**
* Uses direct memory-mapped buffer from file to read something and close it afterwards. * Uses direct memory-mapped buffer from file to read something and close it afterwards.
*/ */
@Throws(IOException::class) @Throws(IOException::class)
inline fun <R> Path.readAsMemory(position: Long = 0, size: Long = Files.size(this), block: Memory.() -> R): R { public inline fun <R> Path.readAsMemory(position: Long = 0, size: Long = Files.size(this), block: Memory.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return FileChannel return FileChannel

View File

@ -1,6 +1,4 @@
plugins { plugins { id("ru.mipt.npm.mpp") }
id("scientifik.mpp")
}
kotlin.sourceSets { kotlin.sourceSets {
commonMain { commonMain {
@ -8,8 +6,9 @@ kotlin.sourceSets {
api(project(":kmath-coroutines")) api(project(":kmath-coroutines"))
} }
} }
jvmMain{
dependencies{ jvmMain {
dependencies {
api("org.apache.commons:commons-rng-sampling:1.3") api("org.apache.commons:commons-rng-sampling:1.3")
api("org.apache.commons:commons-rng-simple:1.3") api("org.apache.commons:commons-rng-simple:1.3")
} }

View File

@ -11,7 +11,7 @@ import kotlin.math.exp
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt import kotlin.math.sqrt
abstract class ContinuousSamplerDistribution : Distribution<Double> { public abstract class ContinuousSamplerDistribution : Distribution<Double> {
private inner class ContinuousSamplerChain(val generator: RandomGenerator) : BlockingRealChain() { private inner class ContinuousSamplerChain(val generator: RandomGenerator) : BlockingRealChain() {
private val sampler = buildCMSampler(generator) private val sampler = buildCMSampler(generator)
@ -26,7 +26,7 @@ abstract class ContinuousSamplerDistribution : Distribution<Double> {
override fun sample(generator: RandomGenerator): BlockingRealChain = ContinuousSamplerChain(generator) override fun sample(generator: RandomGenerator): BlockingRealChain = ContinuousSamplerChain(generator)
} }
abstract class DiscreteSamplerDistribution : Distribution<Int> { public abstract class DiscreteSamplerDistribution : Distribution<Int> {
private inner class ContinuousSamplerChain(val generator: RandomGenerator) : BlockingIntChain() { private inner class ContinuousSamplerChain(val generator: RandomGenerator) : BlockingIntChain() {
private val sampler = buildSampler(generator) private val sampler = buildSampler(generator)
@ -41,7 +41,7 @@ abstract class DiscreteSamplerDistribution : Distribution<Int> {
override fun sample(generator: RandomGenerator): BlockingIntChain = ContinuousSamplerChain(generator) override fun sample(generator: RandomGenerator): BlockingIntChain = ContinuousSamplerChain(generator)
} }
enum class NormalSamplerMethod { public enum class NormalSamplerMethod {
BoxMuller, BoxMuller,
Marsaglia, Marsaglia,
Ziggurat Ziggurat
@ -54,7 +54,7 @@ private fun normalSampler(method: NormalSamplerMethod, provider: UniformRandomPr
NormalSamplerMethod.Ziggurat -> ZigguratNormalizedGaussianSampler(provider) NormalSamplerMethod.Ziggurat -> ZigguratNormalizedGaussianSampler(provider)
} }
fun Distribution.Companion.normal( public fun Distribution.Companion.normal(
method: NormalSamplerMethod = NormalSamplerMethod.Ziggurat method: NormalSamplerMethod = NormalSamplerMethod.Ziggurat
): Distribution<Double> = object : ContinuousSamplerDistribution() { ): Distribution<Double> = object : ContinuousSamplerDistribution() {
override fun buildCMSampler(generator: RandomGenerator): ContinuousSampler { override fun buildCMSampler(generator: RandomGenerator): ContinuousSampler {
@ -67,7 +67,7 @@ fun Distribution.Companion.normal(
} }
} }
fun Distribution.Companion.normal( public fun Distribution.Companion.normal(
mean: Double, mean: Double,
sigma: Double, sigma: Double,
method: NormalSamplerMethod = NormalSamplerMethod.Ziggurat method: NormalSamplerMethod = NormalSamplerMethod.Ziggurat
@ -86,7 +86,7 @@ fun Distribution.Companion.normal(
} }
} }
fun Distribution.Companion.poisson( public fun Distribution.Companion.poisson(
lambda: Double lambda: Double
): DiscreteSamplerDistribution = object : DiscreteSamplerDistribution() { ): DiscreteSamplerDistribution = object : DiscreteSamplerDistribution() {

View File

@ -1,6 +1,4 @@
plugins { plugins { id("ru.mipt.npm.jvm") }
id("scientifik.jvm")
}
description = "Binding for https://github.com/JetBrains-Research/viktor" description = "Binding for https://github.com/JetBrains-Research/viktor"

View File

@ -1,14 +1,12 @@
pluginManagement { pluginManagement {
val toolsVersion = "0.6.0-dev-3"
val toolsVersion = "0.5.0"
plugins { plugins {
id("kotlinx.benchmark") version "0.2.0-dev-8" id("kotlinx.benchmark") version "0.2.0-dev-20"
id("scientifik.mpp") version toolsVersion id("ru.mipt.npm.mpp") version toolsVersion
id("scientifik.jvm") version toolsVersion id("ru.mipt.npm.jvm") version toolsVersion
id("scientifik.atomic") version toolsVersion id("ru.mipt.npm.publish") version toolsVersion
id("scientifik.publish") version toolsVersion kotlin("plugin.allopen") version "1.4.0"
kotlin("plugin.allopen") version "1.3.72"
} }
repositories { repositories {
@ -20,17 +18,10 @@ pluginManagement {
maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/mipt-npm/dev")
maven("https://dl.bintray.com/kotlin/kotlinx") maven("https://dl.bintray.com/kotlin/kotlinx")
} }
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"scientifik.mpp", "scientifik.jvm", "scientifik.publish" -> useModule("scientifik:gradle-tools:$toolsVersion")
}
}
}
} }
rootProject.name = "kmath" rootProject.name = "kmath"
include( include(
":kmath-memory", ":kmath-memory",
":kmath-core", ":kmath-core",