diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 9fd90d08b..9f173a046 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -3,7 +3,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { java kotlin("jvm") - kotlin("plugin.allopen") version "1.4.0" + kotlin("plugin.allopen") version "1.4.20-dev-3898-14" id("kotlinx.benchmark") version "0.2.0-dev-20" } @@ -13,6 +13,7 @@ repositories { maven("http://dl.bintray.com/kyonifer/maven") maven("https://dl.bintray.com/mipt-npm/scientifik") maven("https://dl.bintray.com/mipt-npm/dev") + maven("https://dl.bintray.com/kotlin/kotlin-dev/") mavenCentral() } @@ -55,9 +56,4 @@ kotlin.sourceSets.all { } } -tasks.withType { - kotlinOptions { - jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn" - } -} +tasks.withType { kotlinOptions.jvmTarget = "11" } diff --git a/kmath-ast/src/commonMain/kotlin/scientifik/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/scientifik/kmath/ast/MstAlgebra.kt index e4480e608..7d13a2b25 100644 --- a/kmath-ast/src/commonMain/kotlin/scientifik/kmath/ast/MstAlgebra.kt +++ b/kmath-ast/src/commonMain/kotlin/scientifik/kmath/ast/MstAlgebra.kt @@ -37,7 +37,7 @@ public object MstSpace : Space, NumericAlgebra { /** * [Ring] over [MST] nodes. */ -object MstRing : Ring, NumericAlgebra { +public object MstRing : Ring, NumericAlgebra { override val zero: MST = number(0.0) override val one: MST = number(1.0) @@ -58,18 +58,18 @@ object MstRing : Ring, NumericAlgebra { /** * [Field] over [MST] nodes. */ -object MstField : Field { - override val zero: MST = number(0.0) - override val one: MST = number(1.0) +public object MstField : Field { + public override val zero: MST = number(0.0) + public override val one: MST = number(1.0) - override fun symbol(value: String): MST = MstRing.symbol(value) - override fun number(value: Number): MST = MstRing.number(value) - override fun add(a: MST, b: MST): MST = MstRing.add(a, b) - override fun multiply(a: MST, k: Number): MST = MstRing.multiply(a, k) - override fun multiply(a: MST, b: MST): MST = MstRing.multiply(a, b) - override fun divide(a: MST, b: MST): MST = binaryOperation(FieldOperations.DIV_OPERATION, a, b) + public override fun symbol(value: String): MST = MstRing.symbol(value) + public override fun number(value: Number): MST = MstRing.number(value) + public override fun add(a: MST, b: MST): MST = MstRing.add(a, b) + public override fun multiply(a: MST, k: Number): MST = MstRing.multiply(a, k) + public override fun multiply(a: MST, b: MST): MST = MstRing.multiply(a, b) + public override fun divide(a: MST, b: MST): MST = binaryOperation(FieldOperations.DIV_OPERATION, a, b) - override fun binaryOperation(operation: String, left: MST, right: MST): MST = + public override fun binaryOperation(operation: String, left: MST, right: MST): MST = MstRing.binaryOperation(operation, left, right) override fun unaryOperation(operation: String, arg: MST): MST = MstRing.unaryOperation(operation, arg) @@ -78,7 +78,7 @@ object MstField : Field { /** * [ExtendedField] over [MST] nodes. */ -object MstExtendedField : ExtendedField { +public object MstExtendedField : ExtendedField { override val zero: MST = number(0.0) override val one: MST = number(1.0) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/HyperSquareDomain.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/HyperSquareDomain.kt index e118282bf..61d443ff3 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/HyperSquareDomain.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/HyperSquareDomain.kt @@ -26,22 +26,21 @@ import scientifik.kmath.structures.indices * @author Alexander Nozik */ public class HyperSquareDomain(private val lower: RealBuffer, private val upper: RealBuffer) : RealDomain { + public override val dimension: Int get() = lower.size - override operator fun contains(point: Point): Boolean = point.indices.all { i -> + public override operator fun contains(point: Point): Boolean = point.indices.all { i -> point[i] in lower[i]..upper[i] } - override val dimension: Int get() = lower.size + public override fun getLowerBound(num: Int, point: Point): Double? = lower[num] - override fun getLowerBound(num: Int, point: Point): Double? = lower[num] + public override fun getLowerBound(num: Int): Double? = lower[num] - override fun getLowerBound(num: Int): Double? = lower[num] + public override fun getUpperBound(num: Int, point: Point): Double? = upper[num] - override fun getUpperBound(num: Int, point: Point): Double? = upper[num] + public override fun getUpperBound(num: Int): Double? = upper[num] - override fun getUpperBound(num: Int): Double? = upper[num] - - override fun nearestInDomain(point: Point): Point { + public override fun nearestInDomain(point: Point): Point { val res = DoubleArray(point.size) { i -> when { point[i] < lower[i] -> lower[i] @@ -53,16 +52,14 @@ public class HyperSquareDomain(private val lower: RealBuffer, private val upper: return RealBuffer(*res) } - override fun volume(): Double { + public override fun volume(): Double { var res = 1.0 + for (i in 0 until dimension) { - if (lower[i].isInfinite() || upper[i].isInfinite()) { - return Double.POSITIVE_INFINITY - } - if (upper[i] > lower[i]) { - res *= upper[i] - lower[i] - } + if (lower[i].isInfinite() || upper[i].isInfinite()) return Double.POSITIVE_INFINITY + if (upper[i] > lower[i]) res *= upper[i] - lower[i] } + return res } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/UnconstrainedDomain.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/UnconstrainedDomain.kt index 5c9170663..c637795df 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/UnconstrainedDomain.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/UnconstrainedDomain.kt @@ -17,18 +17,18 @@ package scientifik.kmath.domains import scientifik.kmath.linear.Point -public class UnconstrainedDomain(override val dimension: Int) : RealDomain { - override operator fun contains(point: Point): Boolean = true +public class UnconstrainedDomain(public override val dimension: Int) : RealDomain { + public override operator fun contains(point: Point): Boolean = true - override fun getLowerBound(num: Int, point: Point): Double? = Double.NEGATIVE_INFINITY + public override fun getLowerBound(num: Int, point: Point): Double? = Double.NEGATIVE_INFINITY - override fun getLowerBound(num: Int): Double? = Double.NEGATIVE_INFINITY + public override fun getLowerBound(num: Int): Double? = Double.NEGATIVE_INFINITY - override fun getUpperBound(num: Int, point: Point): Double? = Double.POSITIVE_INFINITY + public override fun getUpperBound(num: Int, point: Point): Double? = Double.POSITIVE_INFINITY - override fun getUpperBound(num: Int): Double? = Double.POSITIVE_INFINITY + public override fun getUpperBound(num: Int): Double? = Double.POSITIVE_INFINITY - override fun nearestInDomain(point: Point): Point = point + public override fun nearestInDomain(point: Point): Point = point - override fun volume(): Double = Double.POSITIVE_INFINITY + public override fun volume(): Double = Double.POSITIVE_INFINITY } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/UnivariateDomain.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/UnivariateDomain.kt index 5b47476d8..066a8ae25 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/UnivariateDomain.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/domains/UnivariateDomain.kt @@ -4,16 +4,20 @@ import scientifik.kmath.linear.Point import scientifik.kmath.structures.asBuffer public inline class UnivariateDomain(public val range: ClosedFloatingPointRange) : RealDomain { + public override val dimension: Int + get() = 1 + public operator fun contains(d: Double): Boolean = range.contains(d) - override operator fun contains(point: Point): Boolean { + public override operator fun contains(point: Point): Boolean { require(point.size == 0) return contains(point[0]) } - override fun nearestInDomain(point: Point): Point { + public override fun nearestInDomain(point: Point): Point { require(point.size == 1) val value = point[0] + return when { value in range -> point value >= range.endInclusive -> doubleArrayOf(range.endInclusive).asBuffer() @@ -21,27 +25,25 @@ public inline class UnivariateDomain(public val range: ClosedFloatingPointRange< } } - override fun getLowerBound(num: Int, point: Point): Double? { + public override fun getLowerBound(num: Int, point: Point): Double? { require(num == 0) return range.start } - override fun getUpperBound(num: Int, point: Point): Double? { + public override fun getUpperBound(num: Int, point: Point): Double? { require(num == 0) return range.endInclusive } - override fun getLowerBound(num: Int): Double? { + public override fun getLowerBound(num: Int): Double? { require(num == 0) return range.start } - override fun getUpperBound(num: Int): Double? { + public override fun getUpperBound(num: Int): Double? { require(num == 0) return range.endInclusive } - override fun volume(): Double = range.endInclusive - range.start - - override val dimension: Int get() = 1 + public override fun volume(): Double = range.endInclusive - range.start } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/FunctionalExpressionAlgebra.kt index 58f874671..3804819e6 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -4,7 +4,8 @@ import scientifik.kmath.operations.* internal class FunctionalUnaryOperation(val context: Algebra, val name: String, private val expr: Expression) : Expression { - override operator fun invoke(arguments: Map): T = context.unaryOperation(name, expr.invoke(arguments)) + public override operator fun invoke(arguments: Map): T = + context.unaryOperation(name, expr.invoke(arguments)) } internal class FunctionalBinaryOperation( @@ -13,17 +14,17 @@ internal class FunctionalBinaryOperation( val first: Expression, val second: Expression ) : Expression { - override operator fun invoke(arguments: Map): T = + public override operator fun invoke(arguments: Map): T = context.binaryOperation(name, first.invoke(arguments), second.invoke(arguments)) } internal class FunctionalVariableExpression(val name: String, val default: T? = null) : Expression { - override operator fun invoke(arguments: Map): T = + public override operator fun invoke(arguments: Map): T = arguments[name] ?: default ?: error("Parameter not found: $name") } internal class FunctionalConstantExpression(val value: T) : Expression { - override operator fun invoke(arguments: Map): T = value + public override operator fun invoke(arguments: Map): T = value } internal class FunctionalConstProductExpression( @@ -31,7 +32,7 @@ internal class FunctionalConstProductExpression( private val expr: Expression, val const: Number ) : Expression { - override operator fun invoke(arguments: Map): T = context.multiply(expr.invoke(arguments), const) + public override operator fun invoke(arguments: Map): T = context.multiply(expr.invoke(arguments), const) } /** @@ -44,23 +45,23 @@ public abstract class FunctionalExpressionAlgebra>(public val /** * Builds an Expression of constant expression which does not depend on arguments. */ - override fun const(value: T): Expression = FunctionalConstantExpression(value) + public override fun const(value: T): Expression = FunctionalConstantExpression(value) /** * Builds an Expression to access a variable. */ - override fun variable(name: String, default: T?): Expression = FunctionalVariableExpression(name, default) + public override fun variable(name: String, default: T?): Expression = FunctionalVariableExpression(name, default) /** * Builds an Expression of dynamic call of binary operation [operation] on [left] and [right]. */ - override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = + public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = FunctionalBinaryOperation(algebra, operation, left, right) /** * Builds an Expression of dynamic call of unary operation with name [operation] on [arg]. */ - override fun unaryOperation(operation: String, arg: Expression): Expression = + public override fun unaryOperation(operation: String, arg: Expression): Expression = FunctionalUnaryOperation(algebra, operation, arg) } @@ -69,18 +70,18 @@ public abstract class FunctionalExpressionAlgebra>(public val */ public open class FunctionalExpressionSpace>(algebra: A) : FunctionalExpressionAlgebra(algebra), Space> { - override val zero: Expression get() = const(algebra.zero) + public override val zero: Expression get() = const(algebra.zero) /** * Builds an Expression of addition of two another expressions. */ - override fun add(a: Expression, b: Expression): Expression = + public override fun add(a: Expression, b: Expression): Expression = binaryOperation(SpaceOperations.PLUS_OPERATION, a, b) /** * Builds an Expression of multiplication of expression by number. */ - override fun multiply(a: Expression, k: Number): Expression = + public override fun multiply(a: Expression, k: Number): Expression = FunctionalConstProductExpression(algebra, a, k) public operator fun Expression.plus(arg: T): Expression = this + const(arg) @@ -88,31 +89,31 @@ public open class FunctionalExpressionSpace>(algebra: A) : public operator fun T.plus(arg: Expression): Expression = arg + this public operator fun T.minus(arg: Expression): Expression = arg - this - override fun unaryOperation(operation: String, arg: Expression): Expression = + public override fun unaryOperation(operation: String, arg: Expression): Expression = super.unaryOperation(operation, arg) - override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = + public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = super.binaryOperation(operation, left, right) } public open class FunctionalExpressionRing(algebra: A) : FunctionalExpressionSpace(algebra), Ring> where A : Ring, A : NumericAlgebra { - override val one: Expression + public override val one: Expression get() = const(algebra.one) /** * Builds an Expression of multiplication of two expressions. */ - override fun multiply(a: Expression, b: Expression): Expression = + public override fun multiply(a: Expression, b: Expression): Expression = binaryOperation(RingOperations.TIMES_OPERATION, a, b) public operator fun Expression.times(arg: T): Expression = this * const(arg) public operator fun T.times(arg: Expression): Expression = arg * this - override fun unaryOperation(operation: String, arg: Expression): Expression = + public override fun unaryOperation(operation: String, arg: Expression): Expression = super.unaryOperation(operation, arg) - override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = + public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = super.binaryOperation(operation, left, right) } @@ -122,38 +123,38 @@ public open class FunctionalExpressionField(algebra: A) : /** * Builds an Expression of division an expression by another one. */ - override fun divide(a: Expression, b: Expression): Expression = + public override fun divide(a: Expression, b: Expression): Expression = binaryOperation(FieldOperations.DIV_OPERATION, a, b) public operator fun Expression.div(arg: T): Expression = this / const(arg) public operator fun T.div(arg: Expression): Expression = arg / this - override fun unaryOperation(operation: String, arg: Expression): Expression = + public override fun unaryOperation(operation: String, arg: Expression): Expression = super.unaryOperation(operation, arg) - override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = + public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = super.binaryOperation(operation, left, right) } public open class FunctionalExpressionExtendedField(algebra: A) : FunctionalExpressionField(algebra), ExtendedField> where A : ExtendedField, A : NumericAlgebra { - override fun sin(arg: Expression): Expression = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg) - override fun cos(arg: Expression): Expression = unaryOperation(TrigonometricOperations.COS_OPERATION, arg) - override fun asin(arg: Expression): Expression = unaryOperation(TrigonometricOperations.ASIN_OPERATION, arg) - override fun acos(arg: Expression): Expression = unaryOperation(TrigonometricOperations.ACOS_OPERATION, arg) - override fun atan(arg: Expression): Expression = unaryOperation(TrigonometricOperations.ATAN_OPERATION, arg) + public override fun sin(arg: Expression): Expression = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg) + public override fun cos(arg: Expression): Expression = unaryOperation(TrigonometricOperations.COS_OPERATION, arg) + public override fun asin(arg: Expression): Expression = unaryOperation(TrigonometricOperations.ASIN_OPERATION, arg) + public override fun acos(arg: Expression): Expression = unaryOperation(TrigonometricOperations.ACOS_OPERATION, arg) + public override fun atan(arg: Expression): Expression = unaryOperation(TrigonometricOperations.ATAN_OPERATION, arg) - override fun power(arg: Expression, pow: Number): Expression = + public override fun power(arg: Expression, pow: Number): Expression = binaryOperation(PowerOperations.POW_OPERATION, arg, number(pow)) - override fun exp(arg: Expression): Expression = unaryOperation(ExponentialOperations.EXP_OPERATION, arg) - override fun ln(arg: Expression): Expression = unaryOperation(ExponentialOperations.LN_OPERATION, arg) + public override fun exp(arg: Expression): Expression = unaryOperation(ExponentialOperations.EXP_OPERATION, arg) + public override fun ln(arg: Expression): Expression = unaryOperation(ExponentialOperations.LN_OPERATION, arg) - override fun unaryOperation(operation: String, arg: Expression): Expression = + public override fun unaryOperation(operation: String, arg: Expression): Expression = super.unaryOperation(operation, arg) - override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = + public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = super.binaryOperation(operation, left, right) } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt index c28cc5ab7..d053f016c 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt @@ -8,82 +8,82 @@ import scientifik.kmath.structures.* * Basic implementation of Matrix space based on [NDStructure] */ public class BufferMatrixContext>( - override val elementContext: R, + public override val elementContext: R, private val bufferFactory: BufferFactory ) : GenericMatrixContext { - - override fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): BufferMatrix { + public override fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): BufferMatrix { val buffer = bufferFactory(rows * columns) { offset -> initializer(offset / columns, offset % columns) } return BufferMatrix(rows, columns, buffer) } - override fun point(size: Int, initializer: (Int) -> T): Point = bufferFactory(size, initializer) + public override fun point(size: Int, initializer: (Int) -> T): Point = bufferFactory(size, initializer) public companion object } @Suppress("OVERRIDE_BY_INLINE") public object RealMatrixContext : GenericMatrixContext { + public override val elementContext: RealField + get() = RealField - override val elementContext: RealField get() = RealField - - override inline fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> Double): Matrix { + public override inline fun produce( + rows: Int, + columns: Int, + initializer: (i: Int, j: Int) -> Double + ): Matrix { val buffer = RealBuffer(rows * columns) { offset -> initializer(offset / columns, offset % columns) } return BufferMatrix(rows, columns, buffer) } - override inline fun point(size: Int, initializer: (Int) -> Double): Point = RealBuffer(size, initializer) + public override inline fun point(size: Int, initializer: (Int) -> Double): Point = + RealBuffer(size, initializer) } public class BufferMatrix( - override val rowNum: Int, - override val colNum: Int, + public override val rowNum: Int, + public override val colNum: Int, public val buffer: Buffer, - override val features: Set = emptySet() + public override val features: Set = emptySet() ) : FeaturedMatrix { + override val shape: IntArray + get() = intArrayOf(rowNum, colNum) init { - if (buffer.size != rowNum * colNum) { - error("Dimension mismatch for matrix structure") - } + require(buffer.size == rowNum * colNum) { "Dimension mismatch for matrix structure" } } - override val shape: IntArray get() = intArrayOf(rowNum, colNum) - - override fun suggestFeature(vararg features: MatrixFeature): BufferMatrix = + public override fun suggestFeature(vararg features: MatrixFeature): BufferMatrix = BufferMatrix(rowNum, colNum, buffer, this.features + features) - override operator fun get(index: IntArray): T = get(index[0], index[1]) + public override operator fun get(index: IntArray): T = get(index[0], index[1]) + public override operator fun get(i: Int, j: Int): T = buffer[i * colNum + j] - override operator fun get(i: Int, j: Int): T = buffer[i * colNum + j] - - override fun elements(): Sequence> = sequence { + public override fun elements(): Sequence> = sequence { for (i in 0 until rowNum) for (j in 0 until colNum) yield(intArrayOf(i, j) to get(i, j)) } - override fun equals(other: Any?): Boolean { + public override fun equals(other: Any?): Boolean { if (this === other) return true + return when (other) { is NDStructure<*> -> return NDStructure.equals(this, other) else -> false } } - override fun hashCode(): Int { + public override fun hashCode(): Int { var result = buffer.hashCode() result = 31 * result + features.hashCode() return result } - override fun toString(): String { - return if (rowNum <= 5 && colNum <= 5) { + public override fun toString(): String { + return if (rowNum <= 5 && colNum <= 5) "Matrix(rowsNum = $rowNum, colNum = $colNum, features=$features)\n" + rows.asSequence().joinToString(prefix = "(", postfix = ")", separator = "\n ") { buffer -> buffer.asSequence().joinToString(separator = "\t") { it.toString() } } - } else { - "Matrix(rowsNum = $rowNum, colNum = $colNum, features=$features)" - } + else "Matrix(rowsNum = $rowNum, colNum = $colNum, features=$features)" } } @@ -92,26 +92,21 @@ public class BufferMatrix( */ public infix fun BufferMatrix.dot(other: BufferMatrix): BufferMatrix { require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } - val array = DoubleArray(this.rowNum * other.colNum) //convert to array to insure there is not memory indirection - fun Buffer.unsafeArray(): DoubleArray = if (this is RealBuffer) { + fun Buffer.unsafeArray() = if (this is RealBuffer) array - } else { + else DoubleArray(size) { get(it) } - } val a = this.buffer.unsafeArray() val b = other.buffer.unsafeArray() - for (i in (0 until rowNum)) { - for (j in (0 until other.colNum)) { - for (k in (0 until colNum)) { + for (i in (0 until rowNum)) + for (j in (0 until other.colNum)) + for (k in (0 until colNum)) array[i * other.colNum + j] += a[i * colNum + k] * b[k * other.colNum + j] - } - } - } val buffer = RealBuffer(array) return BufferMatrix(rowNum, other.colNum, buffer) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/FeaturedMatrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/FeaturedMatrix.kt index 3e5116435..2cd507078 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/FeaturedMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/FeaturedMatrix.kt @@ -26,10 +26,8 @@ public interface FeaturedMatrix : Matrix { public companion object } -public inline fun Structure2D.Companion.real(rows: Int, columns: Int, initializer: (Int, Int) -> Double): Matrix { - contract { callsInPlace(initializer) } - return MatrixContext.real.produce(rows, columns, initializer) -} +public inline fun Structure2D.Companion.real(rows: Int, columns: Int, initializer: (Int, Int) -> Double): Matrix = + MatrixContext.real.produce(rows, columns, initializer) /** * Build a square matrix from given elements. diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt index 2bad1aa46..ab23afff0 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt @@ -76,7 +76,6 @@ public inline fun , F : Field> GenericMatrixContext.l matrix: Matrix, checkSingular: (T) -> Boolean ): LUPDecomposition { - contract { callsInPlace(checkSingular) } require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" } val m = matrix.colNum val pivot = IntArray(matrix.rowNum) @@ -153,10 +152,7 @@ public inline fun , F : Field> GenericMatrixContext.l public inline fun , F : Field> GenericMatrixContext.lup( matrix: Matrix, checkSingular: (T) -> Boolean -): LUPDecomposition { - contract { callsInPlace(checkSingular) } - return lup(T::class, matrix, checkSingular) -} +): LUPDecomposition = lup(T::class, matrix, checkSingular) public fun GenericMatrixContext.lup(matrix: Matrix): LUPDecomposition = lup(Double::class, matrix) { it < 1e-11 } @@ -216,7 +212,6 @@ public inline fun , F : Field> GenericMatrixContext b: Matrix, checkSingular: (T) -> Boolean ): Matrix { - contract { callsInPlace(checkSingular) } // Use existing decomposition if it is provided by matrix val decomposition = a.getFeature() ?: lup(T::class, a, checkSingular) return decomposition.solve(T::class, b) @@ -227,10 +222,7 @@ public fun RealMatrixContext.solve(a: Matrix, b: Matrix): Matrix public inline fun , F : Field> GenericMatrixContext.inverse( matrix: Matrix, checkSingular: (T) -> Boolean -): Matrix { - contract { callsInPlace(checkSingular) } - return solve(matrix, one(matrix.rowNum, matrix.colNum), checkSingular) -} +): Matrix = solve(matrix, one(matrix.rowNum, matrix.colNum), checkSingular) public fun RealMatrixContext.inverse(matrix: Matrix): Matrix = solve(matrix, one(matrix.rowNum, matrix.colNum)) { it < 1e-11 } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgebra.kt index 4daa03e5d..607d63bb1 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgebra.kt @@ -19,10 +19,9 @@ public interface LinearSolver { * Convert matrix to vector if it is possible */ public fun Matrix.asPoint(): Point = - if (this.colNum == 1) { + if (this.colNum == 1) VirtualBuffer(rowNum) { get(it, 0) } - } else { + else error("Can't convert matrix with more than one column to vector") - } public fun Point.asMatrix(): VirtualMatrix = VirtualMatrix(size, 1) { i, _ -> get(i) } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/cumulative.kt index f7dfcd781..1712fef58 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/cumulative.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/cumulative.kt @@ -12,10 +12,8 @@ import kotlin.jvm.JvmName * @param R the type of resulting iterable. * @param initial lazy evaluated. */ -public inline fun Iterator.cumulative(initial: R, crossinline operation: (R, T) -> R): Iterator { - contract { callsInPlace(operation) } - - return object : Iterator { +public inline fun Iterator.cumulative(initial: R, crossinline operation: (R, T) -> R): Iterator = + object : Iterator { var state: R = initial override fun hasNext(): Boolean = this@cumulative.hasNext() @@ -25,7 +23,6 @@ public inline fun Iterator.cumulative(initial: R, crossinline operatio return state } } -} public inline fun Iterable.cumulative(initial: R, crossinline operation: (R, T) -> R): Iterable = Iterable { this@cumulative.iterator().cumulative(initial, operation) } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt index 40f974096..1ea105f67 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt @@ -1,5 +1,7 @@ package scientifik.kmath.operations +import kotlin.contracts.contract + /** * Stub for DSL the [Algebra] is. */ diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt index 56ec84f0b..cbee88e38 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt @@ -40,18 +40,17 @@ public class BigInt internal constructor( private val sign: Byte, private val magnitude: Magnitude ) : Comparable { - - override fun compareTo(other: BigInt): Int = when { + public override fun compareTo(other: BigInt): Int = when { (this.sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0 this.sign < other.sign -> -1 this.sign > other.sign -> 1 else -> this.sign * compareMagnitudes(this.magnitude, other.magnitude) } - override fun equals(other: Any?): Boolean = + public override fun equals(other: Any?): Boolean = if (other is BigInt) compareTo(other) == 0 else error("Can't compare KBigInteger to a different type") - override fun hashCode(): Int = magnitude.hashCode() + sign + public override fun hashCode(): Int = magnitude.hashCode() + sign public fun abs(): BigInt = if (sign == 0.toByte()) this else BigInt(1, magnitude) @@ -456,15 +455,11 @@ public fun String.parseBigInteger(): BigInt? { return res * sign } -public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer { - contract { callsInPlace(initializer) } - return boxing(size, initializer) -} +public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer = + boxing(size, initializer) -public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer { - contract { callsInPlace(initializer) } - return boxing(size, initializer) -} +public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer = + boxing(size, initializer) public fun NDAlgebra.Companion.bigInt(vararg shape: Int): BoxingNDRing = BoxingNDRing(shape, BigIntField, Buffer.Companion::bigInt) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt index facc2ad26..20decf0e0 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt @@ -6,7 +6,6 @@ import scientifik.kmath.structures.MutableBuffer import scientifik.memory.MemoryReader import scientifik.memory.MemorySpec import scientifik.memory.MemoryWriter -import kotlin.contracts.contract import kotlin.math.* /** @@ -165,7 +164,8 @@ public object ComplexField : ExtendedField, Norm { * @property re The real part. * @property im The imaginary part. */ -public data class Complex(val re: Double, val im: Double) : FieldElement, Comparable { +public data class Complex(val re: Double, val im: Double) : FieldElement, + Comparable { public constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble()) override val context: ComplexField get() = ComplexField @@ -197,12 +197,8 @@ public data class Complex(val re: Double, val im: Double) : FieldElement Complex): Buffer { - contract { callsInPlace(init) } - return MemoryBuffer.create(Complex, size, init) -} +public inline fun Buffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer = + MemoryBuffer.create(Complex, size, init) -public inline fun MutableBuffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer { - contract { callsInPlace(init) } - return MemoryBuffer.create(Complex, size, init) -} +public inline fun MutableBuffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer = + MemoryBuffer.create(Complex, size, init) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt index 54460a0da..052e32bb9 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt @@ -62,7 +62,7 @@ public interface ExtendedField : ExtendedFieldOperations, Field { * * TODO inline does not work due to compiler bug. Waiting for fix for KT-27586 */ -inline class Real(val value: Double) : FieldElement { +public inline class Real(public val value: Double) : FieldElement { override val context: RealField get() = RealField @@ -70,14 +70,14 @@ inline class Real(val value: Double) : FieldElement { override fun Double.wrap(): Real = Real(value) - companion object + public companion object } /** * A field for [Double] without boxing. Does not produce appropriate field element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object RealField : ExtendedField, Norm { +public object RealField : ExtendedField, Norm { override val zero: Double get() = 0.0 @@ -127,7 +127,7 @@ object RealField : ExtendedField, Norm { * A field for [Float] without boxing. Does not produce appropriate field element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object FloatField : ExtendedField, Norm { +public object FloatField : ExtendedField, Norm { override val zero: Float get() = 0.0f @@ -177,7 +177,7 @@ object FloatField : ExtendedField, Norm { * A field for [Int] without boxing. Does not produce corresponding ring element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object IntRing : Ring, Norm { +public object IntRing : Ring, Norm { override val zero: Int get() = 0 @@ -201,7 +201,7 @@ object IntRing : Ring, Norm { * A field for [Short] without boxing. Does not produce appropriate ring element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object ShortRing : Ring, Norm { +public object ShortRing : Ring, Norm { override val zero: Short get() = 0 @@ -225,7 +225,7 @@ object ShortRing : Ring, Norm { * A field for [Byte] without boxing. Does not produce appropriate ring element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object ByteRing : Ring, Norm { +public object ByteRing : Ring, Norm { override val zero: Byte get() = 0 @@ -249,7 +249,7 @@ object ByteRing : Ring, Norm { * A field for [Double] without boxing. Does not produce appropriate ring element. */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object LongRing : Ring, Norm { +public object LongRing : Ring, Norm { override val zero: Long get() = 0 diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt index 9e44e38aa..de83768a0 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt @@ -59,6 +59,7 @@ public class BoxingNDRing>( transform: R.(T, T) -> T ): BufferedNDRingElement { check(a, b) + return BufferedNDRingElement( this, buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) }) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDAlgebra.kt index ac8ca0db4..4b1a67805 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDAlgebra.kt @@ -5,7 +5,7 @@ import scientifik.kmath.operations.* public interface BufferedNDAlgebra : NDAlgebra> { public val strides: Strides - override fun check(vararg elements: NDBuffer): Unit = + public override fun check(vararg elements: NDBuffer): Unit = require(elements.all { it.strides == strides }) { ("Strides mismatch") } /** @@ -29,7 +29,7 @@ public interface BufferedNDAlgebra : NDAlgebra> { public interface BufferedNDSpace> : NDSpace>, BufferedNDAlgebra { - override fun NDBuffer.toElement(): SpaceElement, *, out BufferedNDSpace> + public override fun NDBuffer.toElement(): SpaceElement, *, out BufferedNDSpace> } public interface BufferedNDRing> : NDRing>, BufferedNDSpace { diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt index 48d15d50a..d44100037 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt @@ -2,8 +2,6 @@ package scientifik.kmath.structures import scientifik.kmath.operations.Complex import scientifik.kmath.operations.complex -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.contract import kotlin.reflect.KClass /** @@ -56,7 +54,8 @@ public interface Buffer { /** * Create a boxing buffer of given type */ - public inline fun boxing(size: Int, initializer: (Int) -> T): Buffer = ListBuffer(List(size, initializer)) + public inline fun boxing(size: Int, initializer: (Int) -> T): Buffer = + ListBuffer(List(size, initializer)) @Suppress("UNCHECKED_CAST") public inline fun auto(type: KClass, size: Int, crossinline initializer: (Int) -> T): Buffer { @@ -115,11 +114,11 @@ public interface MutableBuffer : Buffer { /** * Create a boxing mutable buffer of given type */ - inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = + public inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = MutableListBuffer(MutableList(size, initializer)) @Suppress("UNCHECKED_CAST") - inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer = + public inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer = when (type) { Double::class -> RealBuffer(DoubleArray(size) { initializer(it) as Double }) as MutableBuffer Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as MutableBuffer @@ -132,12 +131,11 @@ public interface MutableBuffer : Buffer { * Create most appropriate mutable buffer for given type avoiding boxing wherever possible */ @Suppress("UNCHECKED_CAST") - inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = + public inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = auto(T::class, size, initializer) - val real: MutableBufferFactory = { size: Int, initializer: (Int) -> Double -> - RealBuffer(DoubleArray(size) { initializer(it) }) - } + public val real: MutableBufferFactory = + { size, initializer -> RealBuffer(DoubleArray(size) { initializer(it) }) } } } @@ -147,7 +145,7 @@ public interface MutableBuffer : Buffer { * @param T the type of elements contained in the buffer. * @property list The underlying list. */ -inline class ListBuffer(val list: List) : Buffer { +public inline class ListBuffer(public val list: List) : Buffer { override val size: Int get() = list.size @@ -158,7 +156,7 @@ inline class ListBuffer(val list: List) : Buffer { /** * Returns an [ListBuffer] that wraps the original list. */ -fun List.asBuffer(): ListBuffer = ListBuffer(this) +public fun List.asBuffer(): ListBuffer = ListBuffer(this) /** * Creates a new [ListBuffer] with the specified [size], where each element is calculated by calling the specified @@ -167,10 +165,7 @@ fun List.asBuffer(): ListBuffer = ListBuffer(this) * The function [init] is called for each array element sequentially starting from the first one. * It should return the value for an array element given its index. */ -inline fun ListBuffer(size: Int, init: (Int) -> T): ListBuffer { - contract { callsInPlace(init) } - return List(size, init).asBuffer() -} +public inline fun ListBuffer(size: Int, init: (Int) -> T): ListBuffer = List(size, init).asBuffer() /** * [MutableBuffer] implementation over [MutableList]. @@ -178,7 +173,7 @@ inline fun ListBuffer(size: Int, init: (Int) -> T): ListBuffer { * @param T the type of elements contained in the buffer. * @property list The underlying list. */ -inline class MutableListBuffer(val list: MutableList) : MutableBuffer { +public inline class MutableListBuffer(public val list: MutableList) : MutableBuffer { override val size: Int get() = list.size @@ -198,7 +193,7 @@ inline class MutableListBuffer(val list: MutableList) : MutableBuffer { * @param T the type of elements contained in the buffer. * @property array The underlying array. */ -class ArrayBuffer(private val array: Array) : MutableBuffer { +public class ArrayBuffer(private val array: Array) : MutableBuffer { // Can't inline because array is invariant override val size: Int get() = array.size diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ComplexNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ComplexNDField.kt index 56fe2a5ac..87dd11f59 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ComplexNDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ComplexNDField.kt @@ -4,7 +4,6 @@ import scientifik.kmath.operations.Complex import scientifik.kmath.operations.ComplexField import scientifik.kmath.operations.FieldElement import scientifik.kmath.operations.complex -import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -98,7 +97,7 @@ public class ComplexNDField(override val shape: IntArray) : /** * Fast element production using function inlining */ -inline fun BufferedNDField.produceInline(crossinline initializer: ComplexField.(Int) -> Complex): ComplexNDElement { +public inline fun BufferedNDField.produceInline(initializer: ComplexField.(Int) -> Complex): ComplexNDElement { val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) } return BufferedNDFieldElement(this, buffer) } @@ -106,14 +105,13 @@ inline fun BufferedNDField.produceInline(crossinline init /** * Map one [ComplexNDElement] using function with indices. */ -inline fun ComplexNDElement.mapIndexed(crossinline transform: ComplexField.(index: IntArray, Complex) -> Complex): ComplexNDElement = +public inline fun ComplexNDElement.mapIndexed(transform: ComplexField.(index: IntArray, Complex) -> Complex): ComplexNDElement = context.produceInline { offset -> transform(strides.index(offset), buffer[offset]) } /** * Map one [ComplexNDElement] using function without indices. */ -inline fun ComplexNDElement.map(crossinline transform: ComplexField.(Complex) -> Complex): ComplexNDElement { - contract { callsInPlace(transform) } +public inline fun ComplexNDElement.map(transform: ComplexField.(Complex) -> Complex): ComplexNDElement { val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.transform(buffer[offset]) } return BufferedNDFieldElement(context, buffer) } @@ -121,10 +119,9 @@ inline fun ComplexNDElement.map(crossinline transform: ComplexField.(Complex) -> /** * Element by element application of any operation on elements to the whole array. Just like in numpy */ -operator fun Function1.invoke(ndElement: ComplexNDElement): ComplexNDElement = +public operator fun Function1.invoke(ndElement: ComplexNDElement): ComplexNDElement = ndElement.map { this@invoke(it) } - /* plus and minus */ /** @@ -142,8 +139,10 @@ public operator fun ComplexNDElement.minus(arg: Double): ComplexNDElement = map public fun NDField.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape) -public fun NDElement.Companion.complex(vararg shape: Int, initializer: ComplexField.(IntArray) -> Complex): ComplexNDElement = - NDField.complex(*shape).produce(initializer) +public fun NDElement.Companion.complex( + vararg shape: Int, + initializer: ComplexField.(IntArray) -> Complex +): ComplexNDElement = NDField.complex(*shape).produce(initializer) /** * Produce a context for n-dimensional operations inside this real field diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/FlaggedBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/FlaggedBuffer.kt index 314f9fd63..d1165b895 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/FlaggedBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/FlaggedBuffer.kt @@ -1,7 +1,5 @@ package scientifik.kmath.structures -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.contract import kotlin.experimental.and /** @@ -34,23 +32,23 @@ public enum class ValueFlag(public val mask: Byte) { /** * A buffer with flagged values. */ -interface FlaggedBuffer : Buffer { - fun getFlag(index: Int): Byte +public interface FlaggedBuffer : Buffer { + public fun getFlag(index: Int): Byte } /** * The value is valid if all flags are down */ -fun FlaggedBuffer<*>.isValid(index: Int): Boolean = getFlag(index) != 0.toByte() +public fun FlaggedBuffer<*>.isValid(index: Int): Boolean = getFlag(index) != 0.toByte() -fun FlaggedBuffer<*>.hasFlag(index: Int, flag: ValueFlag): Boolean = (getFlag(index) and flag.mask) != 0.toByte() +public fun FlaggedBuffer<*>.hasFlag(index: Int, flag: ValueFlag): Boolean = (getFlag(index) and flag.mask) != 0.toByte() -fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, ValueFlag.MISSING) +public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, ValueFlag.MISSING) /** * A real buffer which supports flags for each value like NaN or Missing */ -class FlaggedRealBuffer(val values: DoubleArray, val flags: ByteArray) : FlaggedBuffer, Buffer { +public class FlaggedRealBuffer(public val values: DoubleArray, public val flags: ByteArray) : FlaggedBuffer, Buffer { init { require(values.size == flags.size) { "Values and flags must have the same dimensions" } } @@ -66,9 +64,7 @@ class FlaggedRealBuffer(val values: DoubleArray, val flags: ByteArray) : Flagged }.iterator() } -inline fun FlaggedRealBuffer.forEachValid(block: (Double) -> Unit) { - contract { callsInPlace(block) } - +public inline fun FlaggedRealBuffer.forEachValid(block: (Double) -> Unit) { indices .asSequence() .filter(::isValid) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/FloatBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/FloatBuffer.kt index 9e974c644..48947b8d7 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/FloatBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/FloatBuffer.kt @@ -8,7 +8,7 @@ import kotlin.contracts.contract * * @property array the underlying array. */ -inline class FloatBuffer(val array: FloatArray) : MutableBuffer { +public inline class FloatBuffer(public val array: FloatArray) : MutableBuffer { override val size: Int get() = array.size override operator fun get(index: Int): Float = array[index] @@ -30,20 +30,17 @@ inline class FloatBuffer(val array: FloatArray) : MutableBuffer { * 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. */ -inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer { - contract { callsInPlace(init) } - return FloatBuffer(FloatArray(size) { init(it) }) -} +public inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer = FloatBuffer(FloatArray(size) { init(it) }) /** * Returns a new [FloatBuffer] of given elements. */ -fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats) +public fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats) /** * Returns a [FloatArray] containing all of the elements of this [MutableBuffer]. */ -val MutableBuffer.array: FloatArray +public val MutableBuffer.array: FloatArray get() = (if (this is FloatBuffer) array else FloatArray(size) { get(it) }) /** @@ -52,4 +49,4 @@ val MutableBuffer.array: FloatArray * @receiver the array. * @return the new buffer. */ -fun FloatArray.asBuffer(): FloatBuffer = FloatBuffer(this) +public fun FloatArray.asBuffer(): FloatBuffer = FloatBuffer(this) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/IntBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/IntBuffer.kt index 88a3bd39d..49cc06755 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/IntBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/IntBuffer.kt @@ -1,9 +1,5 @@ package scientifik.kmath.structures -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - /** * Specialized [MutableBuffer] implementation over [IntArray]. * @@ -31,20 +27,17 @@ public inline class IntBuffer(public val array: IntArray) : MutableBuffer { * 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. */ -inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer { - contract { callsInPlace(init) } - return IntBuffer(IntArray(size) { init(it) }) -} +public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffer(IntArray(size) { init(it) }) /** * Returns a new [IntBuffer] of given elements. */ -fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints) +public fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints) /** * Returns a [IntArray] containing all of the elements of this [MutableBuffer]. */ -val MutableBuffer.array: IntArray +public val MutableBuffer.array: IntArray get() = (if (this is IntBuffer) array else IntArray(size) { get(it) }) /** @@ -53,4 +46,4 @@ val MutableBuffer.array: IntArray * @receiver the array. * @return the new buffer. */ -fun IntArray.asBuffer(): IntBuffer = IntBuffer(this) +public fun IntArray.asBuffer(): IntBuffer = IntBuffer(this) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/LongBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/LongBuffer.kt index 17f161d19..0fe975e42 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/LongBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/LongBuffer.kt @@ -31,10 +31,7 @@ public inline class LongBuffer(public val array: LongArray) : MutableBuffer Long): LongBuffer { - contract { callsInPlace(init) } - return LongBuffer(LongArray(size) { init(it) }) -} +public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongBuffer(LongArray(size) { init(it) }) /** * Returns a new [LongBuffer] of given elements. diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt index 83c50b14b..2936932d0 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt @@ -9,7 +9,7 @@ import scientifik.memory.* * @property memory the underlying memory segment. * @property spec the spec of [T] type. */ -open class MemoryBuffer(protected val memory: Memory, protected val spec: MemorySpec) : Buffer { +public open class MemoryBuffer(protected val memory: Memory, protected val spec: MemorySpec) : Buffer { override val size: Int get() = memory.size / spec.objectSize private val reader: MemoryReader = memory.reader() @@ -17,20 +17,17 @@ open class MemoryBuffer(protected val memory: Memory, protected val spe override operator fun get(index: Int): T = reader.read(spec, spec.objectSize * index) override operator fun iterator(): Iterator = (0 until size).asSequence().map { get(it) }.iterator() - companion object { - fun create(spec: MemorySpec, size: Int): MemoryBuffer = + public companion object { + public fun create(spec: MemorySpec, size: Int): MemoryBuffer = MemoryBuffer(Memory.allocate(size * spec.objectSize), spec) - inline fun create( + public inline fun create( spec: MemorySpec, size: Int, - crossinline initializer: (Int) -> T - ): MemoryBuffer = - MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> - (0 until size).forEach { - buffer[it] = initializer(it) - } - } + initializer: (Int) -> T + ): MemoryBuffer = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> + (0 until size).forEach { buffer[it] = initializer(it) } + } } } @@ -41,7 +38,7 @@ open class MemoryBuffer(protected val memory: Memory, protected val spe * @property memory the underlying memory segment. * @property spec the spec of [T] type. */ -class MutableMemoryBuffer(memory: Memory, spec: MemorySpec) : MemoryBuffer(memory, spec), +public class MutableMemoryBuffer(memory: Memory, spec: MemorySpec) : MemoryBuffer(memory, spec), MutableBuffer { private val writer: MemoryWriter = memory.writer() @@ -49,19 +46,16 @@ class MutableMemoryBuffer(memory: Memory, spec: MemorySpec) : Memory override operator fun set(index: Int, value: T): Unit = writer.write(spec, spec.objectSize * index, value) override fun copy(): MutableBuffer = MutableMemoryBuffer(memory.copy(), spec) - companion object { - fun create(spec: MemorySpec, size: Int): MutableMemoryBuffer = + public companion object { + public fun create(spec: MemorySpec, size: Int): MutableMemoryBuffer = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec) - inline fun create( + public inline fun create( spec: MemorySpec, size: Int, crossinline initializer: (Int) -> T - ): MutableMemoryBuffer = - MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> - (0 until size).forEach { - buffer[it] = initializer(it) - } - } + ): MutableMemoryBuffer = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> + (0 until size).forEach { buffer[it] = initializer(it) } + } } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt index a28eda9b9..a6212469d 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt @@ -115,19 +115,18 @@ public interface NDField, N : NDStructure> : Field, NDRing public operator fun T.div(arg: N): N = map(arg) { divide(it, this@div) } - companion object { - - private val realNDFieldCache = HashMap() + public companion object { + private val realNDFieldCache: MutableMap = hashMapOf() /** * Create a nd-field for [Double] values or pull it from cache if it was created previously */ - fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) } + public fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) } /** * Create a nd-field with boxing generic buffer */ - fun > boxing( + public fun > boxing( field: F, vararg shape: Int, bufferFactory: BufferFactory = Buffer.Companion::boxing @@ -137,7 +136,7 @@ public interface NDField, N : NDStructure> : Field, NDRing * Create a most suitable implementation for nd-field using reified class. */ @Suppress("UNCHECKED_CAST") - inline fun > auto(field: F, vararg shape: Int): BufferedNDField = + public inline fun > auto(field: F, vararg shape: Int): BufferedNDField = when { T::class == Double::class -> real(*shape) as BufferedNDField T::class == Complex::class -> complex(*shape) as BufferedNDField diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt index 6cc0a72c0..99a87f374 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt @@ -4,6 +4,7 @@ import scientifik.kmath.operations.Field import scientifik.kmath.operations.RealField import scientifik.kmath.operations.Ring import scientifik.kmath.operations.Space +import kotlin.contracts.contract /** * The root for all [NDStructure] based algebra elements. Does not implement algebra element root because of problems with recursive self-types @@ -11,31 +12,30 @@ import scientifik.kmath.operations.Space * @param C the type of the context for the element * @param N the type of the underlying [NDStructure] */ -interface NDElement> : NDStructure { +public interface NDElement> : NDStructure { + public val context: NDAlgebra - val context: NDAlgebra + public fun unwrap(): N - fun unwrap(): N + public fun N.wrap(): NDElement - fun N.wrap(): NDElement - - companion object { + public companion object { /** * Create a optimized NDArray of doubles */ - fun real(shape: IntArray, initializer: RealField.(IntArray) -> Double = { 0.0 }): RealNDElement = + public fun real(shape: IntArray, initializer: RealField.(IntArray) -> Double = { 0.0 }): RealNDElement = NDField.real(*shape).produce(initializer) - inline fun real1D(dim: Int, crossinline initializer: (Int) -> Double = { _ -> 0.0 }): RealNDElement = + public inline fun real1D(dim: Int, crossinline initializer: (Int) -> Double = { _ -> 0.0 }): RealNDElement = real(intArrayOf(dim)) { initializer(it[0]) } - inline fun real2D( + public inline fun real2D( dim1: Int, dim2: Int, crossinline initializer: (Int, Int) -> Double = { _, _ -> 0.0 } ): RealNDElement = real(intArrayOf(dim1, dim2)) { initializer(it[0], it[1]) } - inline fun real3D( + public inline fun real3D( dim1: Int, dim2: Int, dim3: Int, @@ -46,7 +46,7 @@ interface NDElement> : NDStructure { /** * Simple boxing NDArray */ - fun > boxing( + public fun > boxing( shape: IntArray, field: F, initializer: F.(IntArray) -> T @@ -55,7 +55,7 @@ interface NDElement> : NDStructure { return ndField.produce(initializer) } - inline fun > auto( + public inline fun > auto( shape: IntArray, field: F, noinline initializer: F.(IntArray) -> T @@ -66,17 +66,16 @@ interface NDElement> : NDStructure { } } - -fun > NDElement.mapIndexed(transform: C.(index: IntArray, T) -> T): NDElement = +public fun > NDElement.mapIndexed(transform: C.(index: IntArray, T) -> T): NDElement = context.mapIndexed(unwrap(), transform).wrap() -fun > NDElement.map(transform: C.(T) -> T): NDElement = +public fun > NDElement.map(transform: C.(T) -> T): NDElement = context.map(unwrap(), transform).wrap() /** * Element by element application of any operation on elements to the whole [NDElement] */ -operator fun > Function1.invoke(ndElement: NDElement): NDElement = +public operator fun > Function1.invoke(ndElement: NDElement): NDElement = ndElement.map { value -> this@invoke(value) } /* plus and minus */ @@ -84,13 +83,13 @@ operator fun > Function1.invoke(ndElement: NDElem /** * Summation operation for [NDElement] and single element */ -operator fun , N : NDStructure> NDElement.plus(arg: T): NDElement = +public operator fun , N : NDStructure> NDElement.plus(arg: T): NDElement = map { value -> arg + value } /** * Subtraction operation between [NDElement] and single element */ -operator fun , N : NDStructure> NDElement.minus(arg: T): NDElement = +public operator fun , N : NDStructure> NDElement.minus(arg: T): NDElement = map { value -> arg - value } /* prod and div */ @@ -98,13 +97,13 @@ operator fun , N : NDStructure> NDElement.minus(arg: /** * Product operation for [NDElement] and single element */ -operator fun , N : NDStructure> NDElement.times(arg: T): NDElement = +public operator fun , N : NDStructure> NDElement.times(arg: T): NDElement = map { value -> arg * value } /** * Division operation between [NDElement] and single element */ -operator fun , N : NDStructure> NDElement.div(arg: T): NDElement = +public operator fun , N : NDStructure> NDElement.div(arg: T): NDElement = map { value -> arg / value } // /** diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt index f4eb93b9e..d3007bb09 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt @@ -1,6 +1,5 @@ package scientifik.kmath.structures -import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import kotlin.jvm.JvmName import kotlin.reflect.KClass @@ -12,17 +11,17 @@ import kotlin.reflect.KClass * * @param T the type of items. */ -interface NDStructure { +public interface NDStructure { /** * The shape of structure, i.e. non-empty sequence of non-negative integers that specify sizes of dimensions of * this structure. */ - val shape: IntArray + public val shape: IntArray /** * The count of dimensions in this structure. It should be equal to size of [shape]. */ - val dimension: Int get() = shape.size + public val dimension: Int get() = shape.size /** * Returns the value at the specified indices. @@ -30,24 +29,24 @@ interface NDStructure { * @param index the indices. * @return the value. */ - operator fun get(index: IntArray): T + public operator fun get(index: IntArray): T /** * Returns the sequence of all the elements associated by their indices. * * @return the lazy sequence of pairs of indices to values. */ - fun elements(): Sequence> + public fun elements(): Sequence> override fun equals(other: Any?): Boolean override fun hashCode(): Int - companion object { + public companion object { /** * Indicates whether some [NDStructure] is equal to another one. */ - fun equals(st1: NDStructure<*>, st2: NDStructure<*>): Boolean { + public fun equals(st1: NDStructure<*>, st2: NDStructure<*>): Boolean { if (st1 === st2) return true // fast comparison of buffers if possible @@ -68,7 +67,7 @@ interface NDStructure { * * Strides should be reused if possible. */ - fun build( + public fun build( strides: Strides, bufferFactory: BufferFactory = Buffer.Companion::boxing, initializer: (IntArray) -> T @@ -78,39 +77,39 @@ interface NDStructure { /** * Inline create NDStructure with non-boxing buffer implementation if it is possible */ - inline fun auto( + public inline fun auto( strides: Strides, crossinline initializer: (IntArray) -> T ): BufferNDStructure = BufferNDStructure(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) }) - inline fun auto( + public inline fun auto( type: KClass, strides: Strides, crossinline initializer: (IntArray) -> T ): BufferNDStructure = BufferNDStructure(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) }) - fun build( + public fun build( shape: IntArray, bufferFactory: BufferFactory = Buffer.Companion::boxing, initializer: (IntArray) -> T ): BufferNDStructure = build(DefaultStrides(shape), bufferFactory, initializer) - inline fun auto( + public inline fun auto( shape: IntArray, crossinline initializer: (IntArray) -> T ): BufferNDStructure = auto(DefaultStrides(shape), initializer) @JvmName("autoVarArg") - inline fun auto( + public inline fun auto( vararg shape: Int, crossinline initializer: (IntArray) -> T ): BufferNDStructure = auto(DefaultStrides(shape), initializer) - inline fun auto( + public inline fun auto( type: KClass, vararg shape: Int, crossinline initializer: (IntArray) -> T @@ -125,68 +124,68 @@ interface NDStructure { * @param index the indices. * @return the value. */ -operator fun NDStructure.get(vararg index: Int): T = get(index) +public operator fun NDStructure.get(vararg index: Int): T = get(index) /** * Represents mutable [NDStructure]. */ -interface MutableNDStructure : NDStructure { +public interface MutableNDStructure : NDStructure { /** * Inserts an item at the specified indices. * * @param index the indices. * @param value the value. */ - operator fun set(index: IntArray, value: T) + public operator fun set(index: IntArray, value: T) } -inline fun MutableNDStructure.mapInPlace(action: (IntArray, T) -> T) { - contract { callsInPlace(action) } +public inline fun MutableNDStructure.mapInPlace(action: (IntArray, T) -> T): Unit = elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } -} /** * A way to convert ND index to linear one and back. */ -interface Strides { +public interface Strides { /** * Shape of NDstructure */ - val shape: IntArray + public val shape: IntArray /** * Array strides */ - val strides: List + public val strides: List /** * Get linear index from multidimensional index */ - fun offset(index: IntArray): Int + public fun offset(index: IntArray): Int /** * Get multidimensional from linear */ - fun index(offset: Int): IntArray + public fun index(offset: Int): IntArray /** * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides */ - val linearSize: Int + public val linearSize: Int + + // TODO introduce a fast way to calculate index of the next element? /** * Iterate over ND indices in a natural order */ - fun indices(): Sequence { - //TODO introduce a fast way to calculate index of the next element? - return (0 until linearSize).asSequence().map { index(it) } - } + public fun indices(): Sequence = (0 until linearSize).asSequence().map { index(it) } } /** * Simple implementation of [Strides]. */ -class DefaultStrides private constructor(override val shape: IntArray) : Strides { +public class DefaultStrides private constructor(override val shape: IntArray) : Strides { + override val linearSize: Int + get() = strides[shape.size] + /** * Strides for memory access */ @@ -194,6 +193,7 @@ class DefaultStrides private constructor(override val shape: IntArray) : Strides sequence { var current = 1 yield(1) + shape.forEach { current *= it yield(current) @@ -212,17 +212,16 @@ class DefaultStrides private constructor(override val shape: IntArray) : Strides val res = IntArray(shape.size) var current = offset var strideIndex = strides.size - 2 + while (strideIndex >= 0) { res[strideIndex] = (current / strides[strideIndex]) current %= strides[strideIndex] strideIndex-- } + return res } - override val linearSize: Int - get() = strides[shape.size] - override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is DefaultStrides) return false @@ -232,13 +231,14 @@ class DefaultStrides private constructor(override val shape: IntArray) : Strides override fun hashCode(): Int = shape.contentHashCode() - companion object { + public companion object { private val defaultStridesCache = HashMap() /** * Cached builder for default strides */ - operator fun invoke(shape: IntArray): Strides = defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } + public operator fun invoke(shape: IntArray): Strides = + defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } } } @@ -247,16 +247,16 @@ class DefaultStrides private constructor(override val shape: IntArray) : Strides * * @param T the type of items. */ -abstract class NDBuffer : NDStructure { +public abstract class NDBuffer : NDStructure { /** * The underlying buffer. */ - abstract val buffer: Buffer + public abstract val buffer: Buffer /** * The strides to access elements of [Buffer] by linear indices. */ - abstract val strides: Strides + public abstract val strides: Strides override operator fun get(index: IntArray): T = buffer[strides.offset(index)] @@ -278,7 +278,7 @@ abstract class NDBuffer : NDStructure { /** * Boxing generic [NDStructure] */ -class BufferNDStructure( +public class BufferNDStructure( override val strides: Strides, override val buffer: Buffer ) : NDBuffer() { @@ -292,13 +292,13 @@ class BufferNDStructure( /** * Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferNDStructure] */ -inline fun NDStructure.mapToBuffer( +public inline fun NDStructure.mapToBuffer( factory: BufferFactory = Buffer.Companion::auto, crossinline transform: (T) -> R ): BufferNDStructure { - return if (this is BufferNDStructure) { + return if (this is BufferNDStructure) BufferNDStructure(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) }) - } else { + else { val strides = DefaultStrides(shape) BufferNDStructure(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) } @@ -307,7 +307,7 @@ inline fun NDStructure.mapToBuffer( /** * Mutable ND buffer based on linear [MutableBuffer]. */ -class MutableBufferNDStructure( +public class MutableBufferNDStructure( override val strides: Strides, override val buffer: MutableBuffer ) : NDBuffer(), MutableNDStructure { @@ -321,7 +321,7 @@ class MutableBufferNDStructure( override operator fun set(index: IntArray, value: T): Unit = buffer.set(strides.offset(index), value) } -inline fun NDStructure.combine( +public inline fun NDStructure.combine( struct: NDStructure, crossinline block: (T, T) -> T ): NDStructure { diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBuffer.kt index cba8e9689..050e5eddb 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBuffer.kt @@ -1,14 +1,11 @@ package scientifik.kmath.structures -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.contract - /** * Specialized [MutableBuffer] implementation over [DoubleArray]. * * @property array the underlying array. */ -inline class RealBuffer(val array: DoubleArray) : MutableBuffer { +public inline class RealBuffer(public val array: DoubleArray) : MutableBuffer { override val size: Int get() = array.size override operator fun get(index: Int): Double = array[index] @@ -30,20 +27,17 @@ inline class RealBuffer(val array: DoubleArray) : MutableBuffer { * 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. */ -inline fun RealBuffer(size: Int, init: (Int) -> Double): RealBuffer { - contract { callsInPlace(init) } - return RealBuffer(DoubleArray(size) { init(it) }) -} +public inline fun RealBuffer(size: Int, init: (Int) -> Double): RealBuffer = RealBuffer(DoubleArray(size) { init(it) }) /** * Returns a new [RealBuffer] of given elements. */ -fun RealBuffer(vararg doubles: Double): RealBuffer = RealBuffer(doubles) +public fun RealBuffer(vararg doubles: Double): RealBuffer = RealBuffer(doubles) /** * Returns a [DoubleArray] containing all of the elements of this [MutableBuffer]. */ -val MutableBuffer.array: DoubleArray +public val MutableBuffer.array: DoubleArray get() = (if (this is RealBuffer) array else DoubleArray(size) { get(it) }) /** @@ -52,4 +46,4 @@ val MutableBuffer.array: DoubleArray * @receiver the array. * @return the new buffer. */ -fun DoubleArray.asBuffer(): RealBuffer = RealBuffer(this) +public fun DoubleArray.asBuffer(): RealBuffer = RealBuffer(this) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBufferField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBufferField.kt index a11826e7e..db79c6b78 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBufferField.kt @@ -4,11 +4,10 @@ import scientifik.kmath.operations.ExtendedField import scientifik.kmath.operations.ExtendedFieldOperations import kotlin.math.* - /** * [ExtendedFieldOperations] over [RealBuffer]. */ -object RealBufferFieldOperations : ExtendedFieldOperations> { +public object RealBufferFieldOperations : ExtendedFieldOperations> { override fun add(a: Buffer, b: Buffer): RealBuffer { require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " @@ -73,9 +72,8 @@ object RealBufferFieldOperations : ExtendedFieldOperations> { override fun asin(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array RealBuffer(DoubleArray(arg.size) { asin(array[it]) }) - } else { + } else RealBuffer(DoubleArray(arg.size) { asin(arg[it]) }) - } override fun acos(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array @@ -92,37 +90,44 @@ object RealBufferFieldOperations : ExtendedFieldOperations> { override fun sinh(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array RealBuffer(DoubleArray(arg.size) { sinh(array[it]) }) - } else RealBuffer(DoubleArray(arg.size) { sinh(arg[it]) }) + } else + RealBuffer(DoubleArray(arg.size) { sinh(arg[it]) }) override fun cosh(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array RealBuffer(DoubleArray(arg.size) { cosh(array[it]) }) - } else RealBuffer(DoubleArray(arg.size) { cosh(arg[it]) }) + } else + RealBuffer(DoubleArray(arg.size) { cosh(arg[it]) }) override fun tanh(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array RealBuffer(DoubleArray(arg.size) { tanh(array[it]) }) - } else RealBuffer(DoubleArray(arg.size) { tanh(arg[it]) }) + } else + RealBuffer(DoubleArray(arg.size) { tanh(arg[it]) }) override fun asinh(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array RealBuffer(DoubleArray(arg.size) { asinh(array[it]) }) - } else RealBuffer(DoubleArray(arg.size) { asinh(arg[it]) }) + } else + RealBuffer(DoubleArray(arg.size) { asinh(arg[it]) }) override fun acosh(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array RealBuffer(DoubleArray(arg.size) { acosh(array[it]) }) - } else RealBuffer(DoubleArray(arg.size) { acosh(arg[it]) }) + } else + RealBuffer(DoubleArray(arg.size) { acosh(arg[it]) }) override fun atanh(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array RealBuffer(DoubleArray(arg.size) { atanh(array[it]) }) - } else RealBuffer(DoubleArray(arg.size) { atanh(arg[it]) }) + } else + RealBuffer(DoubleArray(arg.size) { atanh(arg[it]) }) override fun power(arg: Buffer, pow: Number): RealBuffer = if (arg is RealBuffer) { val array = arg.array RealBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) }) - } else RealBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) }) + } else + RealBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) }) override fun exp(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array @@ -132,7 +137,8 @@ object RealBufferFieldOperations : ExtendedFieldOperations> { override fun ln(arg: Buffer): RealBuffer = if (arg is RealBuffer) { val array = arg.array RealBuffer(DoubleArray(arg.size) { ln(array[it]) }) - } else RealBuffer(DoubleArray(arg.size) { ln(arg[it]) }) + } else + RealBuffer(DoubleArray(arg.size) { ln(arg[it]) }) } /** @@ -140,7 +146,7 @@ object RealBufferFieldOperations : ExtendedFieldOperations> { * * @property size the size of buffers to operate on. */ -class RealBufferField(val size: Int) : ExtendedField> { +public class RealBufferField(public val size: Int) : ExtendedField> { override val zero: Buffer by lazy { RealBuffer(size) { 0.0 } } override val one: Buffer by lazy { RealBuffer(size) { 1.0 } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt index ac2adbe9b..94855d670 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt @@ -112,26 +112,22 @@ public inline fun RealNDElement.map(crossinline transform: RealField.(Double) -> /** * Element by element application of any operation on elements to the whole array. Just like in numpy. */ -operator fun Function1.invoke(ndElement: RealNDElement): RealNDElement = +public operator fun Function1.invoke(ndElement: RealNDElement): RealNDElement = ndElement.map { this@invoke(it) } - /* plus and minus */ /** * Summation operation for [BufferedNDElement] and single element */ -operator fun RealNDElement.plus(arg: Double): RealNDElement = - map { it + arg } +public operator fun RealNDElement.plus(arg: Double): RealNDElement = map { it + arg } /** * Subtraction operation between [BufferedNDElement] and single element */ -operator fun RealNDElement.minus(arg: Double): RealNDElement = - map { it - arg } +public operator fun RealNDElement.minus(arg: Double): RealNDElement = map { it - arg } /** * Produce a context for n-dimensional operations inside this real field */ - -inline fun RealField.nd(vararg shape: Int, action: RealNDField.() -> R): R = NDField.real(*shape).run(action) +public inline fun RealField.nd(vararg shape: Int, action: RealNDField.() -> R): R = NDField.real(*shape).run(action) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortBuffer.kt index 82deb9275..d1a725556 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortBuffer.kt @@ -1,6 +1,5 @@ package scientifik.kmath.structures -import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract /** @@ -30,10 +29,7 @@ public inline class ShortBuffer(public val array: ShortArray) : MutableBuffer Short): ShortBuffer { - contract { callsInPlace(init) } - return ShortBuffer(ShortArray(size) { init(it) }) -} +public inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer = ShortBuffer(ShortArray(size) { init(it) }) /** * Returns a new [ShortBuffer] of given elements. diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt index 9a2ec1c88..30e87fd6a 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt @@ -2,7 +2,6 @@ package scientifik.kmath.structures import scientifik.kmath.operations.RingElement import scientifik.kmath.operations.ShortRing -import kotlin.contracts.contract public typealias ShortNDElement = BufferedNDRingElement @@ -69,11 +68,8 @@ public class ShortNDRing(override val shape: IntArray) : /** * Fast element production using function inlining. */ -public inline fun BufferedNDRing.produceInline(crossinline initializer: ShortRing.(Int) -> Short): ShortNDElement { - contract { callsInPlace(initializer) } - val array = ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) } - return BufferedNDRingElement(this, ShortBuffer(array)) -} +public inline fun BufferedNDRing.produceInline(crossinline initializer: ShortRing.(Int) -> Short): ShortNDElement = + BufferedNDRingElement(this, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) /** * Element by element application of any operation on elements to the whole array. diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure1D.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure1D.kt index a796c2037..22d0c4750 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure1D.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure1D.kt @@ -3,7 +3,7 @@ package scientifik.kmath.structures /** * A structure that is guaranteed to be one-dimensional */ -interface Structure1D : NDStructure, Buffer { +public interface Structure1D : NDStructure, Buffer { override val dimension: Int get() = 1 override operator fun get(index: IntArray): T { @@ -11,14 +11,13 @@ interface Structure1D : NDStructure, Buffer { return get(index[0]) } - override operator fun iterator(): Iterator = (0 until size).asSequence().map { get(it) }.iterator() + override operator fun iterator(): Iterator = (0 until size).asSequence().map(::get).iterator() } /** * A 1D wrapper for nd-structure */ private inline class Structure1DWrapper(val structure: NDStructure) : Structure1D { - override val shape: IntArray get() = structure.shape override val size: Int get() = structure.shape[0] @@ -45,18 +44,12 @@ private inline class Buffer1DWrapper(val buffer: Buffer) : Structure1D /** * Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch */ -fun NDStructure.as1D(): Structure1D = if (shape.size == 1) { - if (this is NDBuffer) { - Buffer1DWrapper(this.buffer) - } else { - Structure1DWrapper(this) - } -} else { +public fun NDStructure.as1D(): Structure1D = if (shape.size == 1) { + if (this is NDBuffer) Buffer1DWrapper(this.buffer) else Structure1DWrapper(this) +} else error("Can't create 1d-structure from ${shape.size}d-structure") -} - /** * Represent this buffer as 1D structure */ -fun Buffer.asND(): Structure1D = Buffer1DWrapper(this) +public fun Buffer.asND(): Structure1D = Buffer1DWrapper(this) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure2D.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure2D.kt index e0ae4d4a2..7633d8898 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure2D.kt @@ -21,11 +21,8 @@ public interface Structure2D : NDStructure { get() = VirtualBuffer(colNum) { j -> VirtualBuffer(rowNum) { i -> get(i, j) } } override fun elements(): Sequence> = sequence { - for (i in (0 until rowNum)) { - for (j in (0 until colNum)) { - yield(intArrayOf(i, j) to get(i, j)) - } - } + for (i in (0 until rowNum)) + for (j in (0 until colNum)) yield(intArrayOf(i, j) to get(i, j)) } public companion object @@ -45,10 +42,9 @@ private inline class Structure2DWrapper(val structure: NDStructure) : Stru /** * Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch */ -public fun NDStructure.as2D(): Structure2D = if (shape.size == 2) { +public fun NDStructure.as2D(): Structure2D = if (shape.size == 2) Structure2DWrapper(this) -} else { +else error("Can't create 2d-structure from ${shape.size}d-structure") -} public typealias Matrix = Structure2D diff --git a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/coroutines/coroutinesExtra.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/coroutines/coroutinesExtra.kt index 692f89589..86bc2d6e3 100644 --- a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/coroutines/coroutinesExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/coroutines/coroutinesExtra.kt @@ -3,9 +3,8 @@ package scientifik.kmath.coroutines import kotlinx.coroutines.* import kotlinx.coroutines.channels.produce import kotlinx.coroutines.flow.* -import kotlin.contracts.contract -val Dispatchers.Math: CoroutineDispatcher +public val Dispatchers.Math: CoroutineDispatcher get() = Default /** @@ -15,31 +14,25 @@ internal class LazyDeferred(val dispatcher: CoroutineDispatcher, val block: s private var deferred: Deferred? = null internal fun start(scope: CoroutineScope) { - if (deferred == null) { - deferred = scope.async(dispatcher, block = block) - } + if (deferred == null) deferred = scope.async(dispatcher, block = block) } suspend fun await(): T = deferred?.await() ?: error("Coroutine not started") } -class AsyncFlow internal constructor(internal val deferredFlow: Flow>) : Flow { - override suspend fun collect(collector: FlowCollector) { - deferredFlow.collect { collector.emit((it.await())) } - } +public class AsyncFlow internal constructor(internal val deferredFlow: Flow>) : Flow { + override suspend fun collect(collector: FlowCollector): Unit = deferredFlow.collect { collector.emit((it.await())) } } -fun Flow.async( +public fun Flow.async( dispatcher: CoroutineDispatcher = Dispatchers.Default, block: suspend CoroutineScope.(T) -> R ): AsyncFlow { - val flow = map { - LazyDeferred(dispatcher) { block(it) } - } + val flow = map { LazyDeferred(dispatcher) { block(it) } } return AsyncFlow(flow) } -fun AsyncFlow.map(action: (T) -> R): AsyncFlow = +public fun AsyncFlow.map(action: (T) -> R): AsyncFlow = AsyncFlow(deferredFlow.map { input -> //TODO add function composition LazyDeferred(input.dispatcher) { @@ -48,7 +41,7 @@ fun AsyncFlow.map(action: (T) -> R): AsyncFlow = } }) -suspend fun AsyncFlow.collect(concurrency: Int, collector: FlowCollector) { +public suspend fun AsyncFlow.collect(concurrency: Int, collector: FlowCollector) { require(concurrency >= 1) { "Buffer size should be more than 1, but was $concurrency" } coroutineScope { @@ -76,18 +69,14 @@ suspend fun AsyncFlow.collect(concurrency: Int, collector: FlowCollector< } } -suspend inline fun AsyncFlow.collect(concurrency: Int, crossinline action: suspend (value: T) -> Unit) { - contract { callsInPlace(action) } +public suspend inline fun AsyncFlow.collect( + concurrency: Int, + crossinline action: suspend (value: T) -> Unit +): Unit = collect(concurrency, object : FlowCollector { + override suspend fun emit(value: T): Unit = action(value) +}) - collect(concurrency, object : FlowCollector { - override suspend fun emit(value: T): Unit = action(value) - }) -} - -inline fun Flow.mapParallel( +public inline fun Flow.mapParallel( dispatcher: CoroutineDispatcher = Dispatchers.Default, crossinline transform: suspend (T) -> R -): Flow { - contract { callsInPlace(transform) } - return flatMapMerge { value -> flow { emit(transform(value)) } }.flowOn(dispatcher) -} +): Flow = flatMapMerge { value -> flow { emit(transform(value)) } }.flowOn(dispatcher) diff --git a/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/structures/LazyNDStructure.kt b/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/structures/LazyNDStructure.kt index ff732a06b..a607d2d85 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/structures/LazyNDStructure.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/structures/LazyNDStructure.kt @@ -3,38 +3,31 @@ package scientifik.kmath.structures import kotlinx.coroutines.* import scientifik.kmath.coroutines.Math -class LazyNDStructure( - val scope: CoroutineScope, - override val shape: IntArray, - val function: suspend (IntArray) -> T +public class LazyNDStructure( + public val scope: CoroutineScope, + public override val shape: IntArray, + public val function: suspend (IntArray) -> T ) : NDStructure { private val cache: MutableMap> = hashMapOf() - fun deferred(index: IntArray): Deferred = cache.getOrPut(index) { - scope.async(context = Dispatchers.Math) { - function(index) - } + public fun deferred(index: IntArray): Deferred = cache.getOrPut(index) { + scope.async(context = Dispatchers.Math) { function(index) } } - suspend fun await(index: IntArray): T = deferred(index).await() + public suspend fun await(index: IntArray): T = deferred(index).await() + public override operator fun get(index: IntArray): T = runBlocking { deferred(index).await() } - override operator fun get(index: IntArray): T = runBlocking { - deferred(index).await() - } - - override fun elements(): Sequence> { + public override fun elements(): Sequence> { val strides = DefaultStrides(shape) - val res = runBlocking { - strides.indices().toList().map { index -> index to await(index) } - } + val res = runBlocking { strides.indices().toList().map { index -> index to await(index) } } return res.asSequence() } - override fun equals(other: Any?): Boolean { + public override fun equals(other: Any?): Boolean { return NDStructure.equals(this, other as? NDStructure<*> ?: return false) } - override fun hashCode(): Int { + public override fun hashCode(): Int { var result = scope.hashCode() result = 31 * result + shape.contentHashCode() result = 31 * result + function.hashCode() @@ -43,21 +36,21 @@ class LazyNDStructure( } } -fun NDStructure.deferred(index: IntArray): Deferred = +public fun NDStructure.deferred(index: IntArray): Deferred = if (this is LazyNDStructure) this.deferred(index) else CompletableDeferred(get(index)) -suspend fun NDStructure.await(index: IntArray): T = +public suspend fun NDStructure.await(index: IntArray): T = if (this is LazyNDStructure) this.await(index) else get(index) /** * PENDING would benefit from KEEP-176 */ -inline fun NDStructure.mapAsyncIndexed( +public inline fun NDStructure.mapAsyncIndexed( scope: CoroutineScope, crossinline function: suspend (T, index: IntArray) -> R ): LazyNDStructure = LazyNDStructure(scope, shape) { index -> function(get(index), index) } -inline fun NDStructure.mapAsync( +public inline fun NDStructure.mapAsync( scope: CoroutineScope, crossinline function: suspend (T) -> R ): LazyNDStructure = LazyNDStructure(scope, shape) { index -> function(get(index)) } diff --git a/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt index 7b0244bdf..8ebbf47c0 100644 --- a/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt @@ -13,35 +13,36 @@ import scientifik.kmath.structures.Structure2D /** * A matrix with compile-time controlled dimension */ -interface DMatrix : Structure2D { - companion object { +public interface DMatrix : Structure2D { + public companion object { /** * Coerces a regular matrix to a matrix with type-safe dimensions and throws a error if coercion failed */ - inline fun coerce(structure: Structure2D): DMatrix { - if (structure.rowNum != Dimension.dim().toInt()) { - error("Row number mismatch: expected ${Dimension.dim()} but found ${structure.rowNum}") + public inline fun coerce(structure: Structure2D): DMatrix { + require(structure.rowNum == Dimension.dim().toInt()) { + "Row number mismatch: expected ${Dimension.dim()} but found ${structure.rowNum}" } - if (structure.colNum != Dimension.dim().toInt()) { - error("Column number mismatch: expected ${Dimension.dim()} but found ${structure.colNum}") + + require(structure.colNum == Dimension.dim().toInt()) { + "Column number mismatch: expected ${Dimension.dim()} but found ${structure.colNum}" } + return DMatrixWrapper(structure) } /** - * The same as [coerce] but without dimension checks. Use with caution + * The same as [DMatrix.coerce] but without dimension checks. Use with caution */ - fun coerceUnsafe(structure: Structure2D): DMatrix { - return DMatrixWrapper(structure) - } + public fun coerceUnsafe(structure: Structure2D): DMatrix = + DMatrixWrapper(structure) } } /** * An inline wrapper for a Matrix */ -inline class DMatrixWrapper( - val structure: Structure2D +public inline class DMatrixWrapper( + public val structure: Structure2D ) : DMatrix { override val shape: IntArray get() = structure.shape override operator fun get(i: Int, j: Int): T = structure[i, j] @@ -50,25 +51,24 @@ inline class DMatrixWrapper( /** * Dimension-safe point */ -interface DPoint : Point { - companion object { - inline fun coerce(point: Point): DPoint { - if (point.size != Dimension.dim().toInt()) { - error("Vector dimension mismatch: expected ${Dimension.dim()}, but found ${point.size}") +public interface DPoint : Point { + public companion object { + public inline fun coerce(point: Point): DPoint { + require(point.size == Dimension.dim().toInt()) { + "Vector dimension mismatch: expected ${Dimension.dim()}, but found ${point.size}" } + return DPointWrapper(point) } - fun coerceUnsafe(point: Point): DPoint { - return DPointWrapper(point) - } + public fun coerceUnsafe(point: Point): DPoint = DPointWrapper(point) } } /** * Dimension-safe point wrapper */ -inline class DPointWrapper(val point: Point) : +public inline class DPointWrapper(public val point: Point) : DPoint { override val size: Int get() = point.size @@ -81,16 +81,15 @@ inline class DPointWrapper(val point: Point) : /** * Basic operations on dimension-safe matrices. Operates on [Matrix] */ -inline class DMatrixContext>(val context: GenericMatrixContext) { +public inline class DMatrixContext>(public val context: GenericMatrixContext) { + public inline fun Matrix.coerce(): DMatrix { + require(rowNum == Dimension.dim().toInt()) { + "Row number mismatch: expected ${Dimension.dim()} but found $rowNum" + } - inline fun Matrix.coerce(): DMatrix { - check( - rowNum == Dimension.dim().toInt() - ) { "Row number mismatch: expected ${Dimension.dim()} but found $rowNum" } - - check( - colNum == Dimension.dim().toInt() - ) { "Column number mismatch: expected ${Dimension.dim()} but found $colNum" } + require(colNum == Dimension.dim().toInt()) { + "Column number mismatch: expected ${Dimension.dim()} but found $colNum" + } return DMatrix.coerceUnsafe(this) } @@ -98,13 +97,13 @@ inline class DMatrixContext>(val context: GenericMatrixCon /** * Produce a matrix with this context and given dimensions */ - inline fun produce(noinline initializer: (i: Int, j: Int) -> T): DMatrix { + public inline fun produce(noinline initializer: (i: Int, j: Int) -> T): DMatrix { val rows = Dimension.dim() val cols = Dimension.dim() return context.produce(rows.toInt(), cols.toInt(), initializer).coerce() } - inline fun point(noinline initializer: (Int) -> T): DPoint { + public inline fun point(noinline initializer: (Int) -> T): DPoint { val size = Dimension.dim() return DPoint.coerceUnsafe( @@ -115,7 +114,7 @@ inline class DMatrixContext>(val context: GenericMatrixCon ) } - inline infix fun DMatrix.dot( + public inline infix fun DMatrix.dot( other: DMatrix ): DMatrix = context { this@dot dot other }.coerce() diff --git a/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realMatrix.kt b/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realMatrix.kt index a3b41288a..5cecafd2e 100644 --- a/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realMatrix.kt +++ b/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realMatrix.kt @@ -116,16 +116,13 @@ public operator fun Matrix.minus(other: Matrix): RealMatrix = * Operations on columns */ -public inline fun Matrix.appendColumn(crossinline mapper: (Buffer) -> Double): Matrix { - contract { callsInPlace(mapper) } - - return MatrixContext.real.produce(rowNum, colNum + 1) { row, col -> +public inline fun Matrix.appendColumn(crossinline mapper: (Buffer) -> Double): Matrix = + MatrixContext.real.produce(rowNum, colNum + 1) { row, col -> if (col < colNum) this[row, col] else mapper(rows[row]) } -} public fun Matrix.extractColumns(columnRange: IntRange): RealMatrix = MatrixContext.real.produce(rowNum, columnRange.count()) { row, col -> diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt index b11469ccf..52030f0fd 100644 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt @@ -12,11 +12,10 @@ public fun interface PiecewisePolynomial : /** * Ordered list of pieces in piecewise function */ -public class OrderedPiecewisePolynomial>(delimeter: T) : +public class OrderedPiecewisePolynomial>(delimiter: T) : PiecewisePolynomial { - - private val delimiters: ArrayList = arrayListOf(delimeter) - private val pieces: ArrayList> = ArrayList() + private val delimiters: MutableList = arrayListOf(delimiter) + private val pieces: MutableList> = arrayListOf() /** * Dynamically add a piece to the "right" side (beyond maximum argument value of previous piece) @@ -35,14 +34,13 @@ public class OrderedPiecewisePolynomial>(delimeter: T) : } override fun findPiece(arg: T): Polynomial? { - if (arg < delimiters.first() || arg >= delimiters.last()) { + if (arg < delimiters.first() || arg >= delimiters.last()) return null - } else { - for (index in 1 until delimiters.size) { - if (arg < delimiters[index]) { + else { + for (index in 1 until delimiters.size) + if (arg < delimiters[index]) return pieces[index - 1] - } - } + error("Piece not found") } } diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt index 35f1a1e16..25a9a9421 100644 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt @@ -48,9 +48,9 @@ public fun > Polynomial.asFunction(ring: C): (T) -> T = * An algebra for polynomials */ public class PolynomialSpace>(public val ring: C) : Space> { - override val zero: Polynomial = Polynomial(emptyList()) + public override val zero: Polynomial = Polynomial(emptyList()) - override fun add(a: Polynomial, b: Polynomial): Polynomial { + public override fun add(a: Polynomial, b: Polynomial): Polynomial { val dim = max(a.coefficients.size, b.coefficients.size) return ring { @@ -60,7 +60,7 @@ public class PolynomialSpace>(public val ring: C) : Space

, k: Number): Polynomial = + public override fun multiply(a: Polynomial, k: Number): Polynomial = ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * k }) } public operator fun Polynomial.invoke(arg: T): T = value(ring, arg) diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt index 95e734da8..a53cafece 100644 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt @@ -22,7 +22,7 @@ public interface PolynomialInterpolator> : Interpolator } } -fun > PolynomialInterpolator.interpolatePolynomials( +public fun > PolynomialInterpolator.interpolatePolynomials( x: Buffer, y: Buffer ): PiecewisePolynomial { @@ -30,16 +30,16 @@ fun > PolynomialInterpolator.interpolatePolynomials( return interpolatePolynomials(pointSet) } -fun > PolynomialInterpolator.interpolatePolynomials( +public fun > PolynomialInterpolator.interpolatePolynomials( data: Map ): PiecewisePolynomial { val pointSet = BufferXYPointSet(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) return interpolatePolynomials(pointSet) } -fun > PolynomialInterpolator.interpolatePolynomials( +public fun > PolynomialInterpolator.interpolatePolynomials( data: List> ): PiecewisePolynomial { val pointSet = BufferXYPointSet(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) return interpolatePolynomials(pointSet) -} \ No newline at end of file +} diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt index 03a4625fc..4fac86693 100644 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt @@ -9,8 +9,8 @@ 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 */ -public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { - override fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial = algebra { +public class LinearInterpolator>(public override val algebra: Field) : PolynomialInterpolator { + public override fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial = algebra { require(points.size > 0) { "Point array should not be empty" } insureSorted(points) diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt index c8ab42bf4..eec61159d 100644 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt @@ -12,13 +12,13 @@ import scientifik.kmath.structures.MutableBufferFactory * Based on https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java */ public class SplineInterpolator>( - override val algebra: Field, + public override val algebra: Field, public val bufferFactory: MutableBufferFactory ) : PolynomialInterpolator { //TODO possibly optimize zeroed buffers - override fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial = algebra { + public override fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial = algebra { if (points.size < 3) { error("Can't use spline interpolator with less than 3 points") } @@ -41,8 +41,9 @@ public class SplineInterpolator>( // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) - OrderedPiecewisePolynomial(points.x[points.size - 1]).apply { + OrderedPiecewisePolynomial(points.x[points.size - 1]).apply { var cOld = zero + for (j in n - 1 downTo 0) { val c = z[j] - mu[j] * cOld val a = points.y[j] diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt index 19297036b..3c45223d9 100644 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt @@ -14,32 +14,32 @@ public interface XYZPointSet : XYPointSet { } internal fun > insureSorted(points: XYPointSet) { - 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" } } public class NDStructureColumn(public val structure: Structure2D, public val column: Int) : Buffer { + public override val size: Int + get() = structure.rowNum + init { require(column < structure.colNum) { "Column index is outside of structure column range" } } - override val size: Int get() = structure.rowNum - - override operator fun get(index: Int): T = structure[index, column] - - override operator fun iterator(): Iterator = sequence { - repeat(size) { - yield(get(it)) - } - }.iterator() + public override operator fun get(index: Int): T = structure[index, column] + public override operator fun iterator(): Iterator = sequence { repeat(size) { yield(get(it)) } }.iterator() } -public class BufferXYPointSet(override val x: Buffer, override val y: Buffer) : XYPointSet { +public class BufferXYPointSet( + public override val x: Buffer, + public override val y: Buffer +) : XYPointSet { + public override val size: Int + get() = x.size + init { require(x.size == y.size) { "Sizes of x and y buffers should be the same" } } - - override val size: Int - get() = x.size } public fun Structure2D.asXYPointSet(): XYPointSet { diff --git a/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt index 540494caf..3d39de4c9 100644 --- a/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt @@ -6,7 +6,7 @@ import scientifik.kmath.operations.RealField import kotlin.test.Test import kotlin.test.assertEquals -class LinearInterpolatorTest { +internal class LinearInterpolatorTest { @Test fun testInterpolation() { val data = listOf( @@ -15,9 +15,9 @@ class LinearInterpolatorTest { 2.0 to 3.0, 3.0 to 4.0 ) + val polynomial: PiecewisePolynomial = LinearInterpolator(RealField).interpolatePolynomials(data) val function = polynomial.asFunction(RealField) - assertEquals(null, function(-1.0)) assertEquals(0.5, function(0.5)) assertEquals(2.0, function(1.5)) diff --git a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt index 551b877a7..be5bf5740 100644 --- a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt +++ b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt @@ -4,17 +4,16 @@ import org.jetbrains.bio.viktor.F64FlatArray import scientifik.kmath.structures.MutableBuffer @Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") -inline class ViktorBuffer(val flatArray: F64FlatArray) : MutableBuffer { - override val size: Int get() = flatArray.size +public inline class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { + public override val size: Int + get() = flatArray.size + + public override inline fun get(index: Int): Double = flatArray[index] - override inline fun get(index: Int): Double = flatArray[index] override inline fun set(index: Int, value: Double) { flatArray[index] = value } - override fun copy(): MutableBuffer { - return ViktorBuffer(flatArray.copy().flatten()) - } - - override operator fun iterator(): Iterator = flatArray.data.iterator() + public override fun copy(): MutableBuffer = ViktorBuffer(flatArray.copy().flatten()) + public override operator fun iterator(): Iterator = flatArray.data.iterator() } diff --git a/settings.gradle.kts b/settings.gradle.kts index 102cde93f..a09e4e144 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,12 +1,12 @@ pluginManagement { - val toolsVersion = "0.6.0-dev-3" + val toolsVersion = "0.6.0-dev-5" plugins { id("kotlinx.benchmark") version "0.2.0-dev-20" id("ru.mipt.npm.mpp") version toolsVersion id("ru.mipt.npm.jvm") version toolsVersion id("ru.mipt.npm.publish") version toolsVersion - kotlin("plugin.allopen") version "1.4.0" + kotlin("plugin.allopen") version "1.4.20-dev-3898-14" } repositories { @@ -17,6 +17,7 @@ pluginManagement { maven("https://dl.bintray.com/mipt-npm/scientifik") maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/kotlin/kotlinx") + maven("https://dl.bintray.com/kotlin/kotlin-dev/") } }