diff --git a/kmath-core/build.gradle b/kmath-core/build.gradle index 18be067e6..c63e518fc 100644 --- a/kmath-core/build.gradle +++ b/kmath-core/build.gradle @@ -2,11 +2,6 @@ plugins { id 'kotlin-multiplatform' } -repositories { - maven { url = 'http://dl.bintray.com/kotlin/kotlin-eap' } - mavenCentral() -} - kotlin { targets { fromPreset(presets.jvm, 'jvm') diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt index e585b884d..39931b676 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt @@ -1,9 +1,6 @@ package scientifik.kmath.linear -import scientifik.kmath.operations.DoubleField -import scientifik.kmath.operations.Field -import scientifik.kmath.operations.Space -import scientifik.kmath.operations.SpaceElement +import scientifik.kmath.operations.* import scientifik.kmath.structures.* /** @@ -70,8 +67,6 @@ abstract class MatrixSpace(val rows: Int, val columns: Int, val field: result = 31 * result + field.hashCode() return result } - - } infix fun Matrix.dot(b: Matrix): Matrix = this.context.multiply(this, b) @@ -191,11 +186,11 @@ interface Vector : SpaceElement, VectorSpace>, Buffer, typealias NDFieldFactory = (IntArray) -> NDField internal fun genericNDFieldFactory(field: Field): NDFieldFactory = { index -> GenericNDField(index, field) } -internal val realNDFieldFactory: NDFieldFactory = { index -> GenericNDField(index, DoubleField) } +internal val realNDFieldFactory: NDFieldFactory = { index -> ExtendedNDField(index, DoubleField) } /** - * NDArray-based implementation of vector space. By default uses slow [SimpleNDField], but could be overridden with custom [NDField] factory. + * NDArray-based implementation of vector space. By default uses slow [GenericNDField], but could be overridden with custom [NDField] factory. */ class ArrayMatrixSpace( rows: Int, @@ -318,3 +313,8 @@ fun Vector.toMatrix(): Matrix { return Matrix.of(size, 1, context.field) { i, _ -> get(i) } } +object VectorL2Norm: Norm, Double> { + override fun norm(arg: Vector): Double { + return kotlin.math.sqrt(arg.sumByDouble { it.toDouble() }) + } +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Fields.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Fields.kt index eeba76222..3e4f47869 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Fields.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Fields.kt @@ -2,10 +2,20 @@ package scientifik.kmath.operations import kotlin.math.pow +/** + * Advanced Number-like field that implements basic operations + */ +interface ExtendedField : + Field, + TrigonometricOperations, + PowerOperations, + ExponentialOperations + + /** * Field for real values */ -object RealField : Field, TrigonometricOperations, PowerOperations, ExponentialOperations { +object RealField : ExtendedField, Norm { override val zero: Real = Real(0.0) override fun add(a: Real, b: Real): Real = Real(a.value + b.value) override val one: Real = Real(1.0) @@ -13,33 +23,24 @@ object RealField : Field, TrigonometricOperations, PowerOperations { - /* - * The class uses composition instead of inheritance since Double is final - */ - - override fun toByte(): Byte = value.toByte() - override fun toChar(): Char = value.toChar() - override fun toDouble(): Double = value - override fun toFloat(): Float = value.toFloat() - override fun toInt(): Int = value.toInt() - override fun toLong(): Long = value.toLong() - override fun toShort(): Short = value.toShort() +inline class Real(val value: Double) : FieldElement { //values are dynamically calculated to save memory override val self @@ -53,19 +54,21 @@ data class Real(val value: Double) : Number(), FieldElement { /** * A field for double without boxing. Does not produce appropriate field element */ -object DoubleField : Field, TrigonometricOperations, PowerOperations, ExponentialOperations { +object DoubleField : ExtendedField, Norm { override val zero: Double = 0.0 override fun add(a: Double, b: Double): Double = a + b override fun multiply(a: Double, @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") b: Double): Double = a * b override val one: Double = 1.0 override fun divide(a: Double, b: Double): Double = a / b - override fun sin(arg: Double): Double = kotlin.math.sin(arg) + override fun sin(arg: Double): Double = kotlin.math.sin(arg) override fun cos(arg: Double): Double = kotlin.math.cos(arg) - override fun power(arg: Double, pow: Double): Double = arg.pow(pow) + override fun power(arg: Double, pow: Double): Double = arg.pow(pow) - override fun exp(arg: Double): Double =kotlin.math.exp(arg) + override fun exp(arg: Double): Double = kotlin.math.exp(arg) - override fun ln(arg: Double): Double = kotlin.math.ln(arg) + override fun ln(arg: Double): Double = kotlin.math.ln(arg) + + override fun norm(arg: Double): Double = kotlin.math.abs(arg) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt index 7628cb4fc..9e5c8a801 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt @@ -45,4 +45,10 @@ interface ExponentialOperations { } fun >> exp(arg: T): T = arg.context.exp(arg) -fun >> ln(arg: T): T = arg.context.ln(arg) \ No newline at end of file +fun >> ln(arg: T): T = arg.context.ln(arg) + +interface Norm { + fun norm(arg: T): R +} + +fun >, R> norm(arg: T): R = arg.context.norm(arg) \ No newline at end of file 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 3e2712f0c..b68072332 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt @@ -42,6 +42,7 @@ inline class ListBuffer(private val list: MutableList) : MutableBuffer } class ArrayBuffer(private val array: Array) : MutableBuffer { + //Can't inline because array invariant override val size: Int get() = array.size diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt new file mode 100644 index 000000000..6392aeec6 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt @@ -0,0 +1,39 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.* + + +/** + * NDField that supports [ExtendedField] operations on its elements + */ +class ExtendedNDField(shape: IntArray, override val field: ExtendedField) : NDField(shape, field), + TrigonometricOperations>, + PowerOperations>, + ExponentialOperations> { + + override fun produceStructure(initializer: (IntArray) -> N): NDStructure { + return genericNdStructure(shape, initializer) + } + + override fun power(arg: NDArray, pow: Double): NDArray { + return arg.transform { d -> with(field){power(d,pow)} } + } + + override fun exp(arg: NDArray): NDArray { + return arg.transform { d -> with(field){exp(d)} } + } + + override fun ln(arg: NDArray): NDArray { + return arg.transform { d -> with(field){ln(d)} } + } + + override fun sin(arg: NDArray): NDArray { + return arg.transform { d -> with(field){sin(d)} } + } + + override fun cos(arg: NDArray): NDArray { + return arg.transform { d -> with(field){cos(d)} } + } +} + + diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt index 7b991200b..74bffa7ad 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt @@ -1,5 +1,6 @@ package scientifik.kmath.structures +import scientifik.kmath.operations.DoubleField import scientifik.kmath.operations.Field import scientifik.kmath.operations.FieldElement @@ -14,7 +15,7 @@ class ShapeMismatchException(val expected: IntArray, val actual: IntArray) : Run * @param field - operations field defined on individual array element * @param T the type of the element contained in NDArray */ -abstract class NDField(val shape: IntArray, val field: Field) : Field> { +abstract class NDField(val shape: IntArray, open val field: Field) : Field> { abstract fun produceStructure(initializer: (IntArray) -> T): NDStructure @@ -173,7 +174,7 @@ object NDArrays { * Create a platform-optimized NDArray of doubles */ fun realNDArray(shape: IntArray, initializer: (IntArray) -> Double = { 0.0 }): NDArray { - return RealNDField(shape).produce(initializer) + return ExtendedNDField(shape, DoubleField).produce(initializer) } fun real1DArray(dim: Int, initializer: (Int) -> Double = { _ -> 0.0 }): NDArray { @@ -188,7 +189,7 @@ object NDArrays { return realNDArray(intArrayOf(dim1, dim2, dim3)) { initializer(it[0], it[1], it[2]) } } - inline fun produceReal(shape: IntArray, block: RealNDField.() -> RealNDArray) = RealNDField(shape).run(block) + inline fun produceReal(shape: IntArray, block: ExtendedNDField.() -> NDArray) = ExtendedNDField(shape, DoubleField).run(block) // /** // * Simple boxing NDField diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt deleted file mode 100644 index 2ba5fd706..000000000 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt +++ /dev/null @@ -1,46 +0,0 @@ -package scientifik.kmath.structures - -import scientifik.kmath.operations.DoubleField -import scientifik.kmath.operations.ExponentialOperations -import scientifik.kmath.operations.PowerOperations -import scientifik.kmath.operations.TrigonometricOperations -import kotlin.math.* - -typealias RealNDArray = NDArray - - -class RealNDField(shape: IntArray) : NDField(shape, DoubleField), - TrigonometricOperations, - PowerOperations, - ExponentialOperations { - - override fun produceStructure(initializer: (IntArray) -> Double): NDStructure { - return genericNdStructure(shape, initializer) - } - - override fun power(arg: RealNDArray, pow: Double): RealNDArray { - return arg.transform { d -> d.pow(pow) } - } - - override fun exp(arg: RealNDArray): RealNDArray { - return arg.transform { d -> exp(d) } - } - - override fun ln(arg: RealNDArray): RealNDArray { - return arg.transform { d -> ln(d) } - } - - override fun sin(arg: RealNDArray): RealNDArray { - return arg.transform { d -> sin(d) } - } - - override fun cos(arg: RealNDArray): RealNDArray { - return arg.transform { d -> cos(d) } - } - - fun abs(arg: RealNDArray): RealNDArray { - return arg.transform { d -> abs(d) } - } -} - - diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt index b07158cc3..0d33204df 100644 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt @@ -6,9 +6,11 @@ import kotlin.test.assertEquals class RealFieldTest { @Test fun testSqrt() { + + //fails because KT-27586 val sqrt = with(RealField) { - sqrt(25 * one) + sqrt( 25 * one) } - assertEquals(5.0, sqrt.toDouble()) + assertEquals(5.0, sqrt.value) } } \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/RealNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt similarity index 68% rename from kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/RealNDFieldTest.kt rename to kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt index 179fb5ade..844535fa8 100644 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/RealNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt @@ -1,5 +1,8 @@ package scientifik.kmath.structures +import scientifik.kmath.linear.Vector +import scientifik.kmath.linear.VectorL2Norm +import scientifik.kmath.operations.Norm import scientifik.kmath.structures.NDArrays.produceReal import scientifik.kmath.structures.NDArrays.real2DArray import kotlin.math.abs @@ -7,7 +10,7 @@ import kotlin.math.pow import kotlin.test.Test import kotlin.test.assertEquals -class RealNDFieldTest { +class NumberNDFieldTest { val array1 = real2DArray(3, 3) { i, j -> (i + j).toDouble() } val array2 = real2DArray(3, 3) { i, j -> (i - j).toDouble() } @@ -46,14 +49,22 @@ class RealNDFieldTest { @Test fun testLibraryFunction() { val abs: (Double) -> Double = ::abs - val result = abs(array1) - assertEquals(10.0, result[1,1]) + val result = abs(array2) + assertEquals(2.0, result[0,2]) + } + + object L2Norm: Norm, Double> { + override fun norm(arg: NDArray): Double { + return kotlin.math.sqrt(arg.sumByDouble { it.second.toDouble() }) + } } @Test - fun testAbs(){ - val res = produceReal(array1.shape){ - 1 + abs(array1) + exp(array2) + fun testInternalContext(){ + produceReal(array1.shape){ + with(L2Norm) { + 1 + norm(array1) + exp(array2) + } } } } diff --git a/kmath-io/build.gradle b/kmath-io/build.gradle new file mode 100644 index 000000000..d0d93262e --- /dev/null +++ b/kmath-io/build.gradle @@ -0,0 +1,53 @@ +plugins { + id 'kotlin-multiplatform' +} + +kotlin { + targets { + fromPreset(presets.jvm, 'jvm') + fromPreset(presets.js, 'js') + // For ARM, preset should be changed to presets.iosArm32 or presets.iosArm64 + // For Linux, preset should be changed to e.g. presets.linuxX64 + // For MacOS, preset should be changed to e.g. presets.macosX64 + //fromPreset(presets.mingwX64, 'mingw') + } + sourceSets { + commonMain { + dependencies { + api project(":kmath-core") + implementation 'org.jetbrains.kotlin:kotlin-stdlib-common' + } + } + commonTest { + dependencies { + implementation 'org.jetbrains.kotlin:kotlin-test-common' + implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common' + } + } + jvmMain { + dependencies { + implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' + } + } + jvmTest { + dependencies { + implementation 'org.jetbrains.kotlin:kotlin-test' + implementation 'org.jetbrains.kotlin:kotlin-test-junit' + } + } + jsMain { + dependencies { + implementation 'org.jetbrains.kotlin:kotlin-stdlib-js' + } + } + jsTest { + dependencies { + implementation 'org.jetbrains.kotlin:kotlin-test-js' + } + } +// mingwMain { +// } +// mingwTest { +// } + } +} diff --git a/kmath-jmh/build.gradle b/kmath-jmh/build.gradle index a16bf3022..97337cb40 100644 --- a/kmath-jmh/build.gradle +++ b/kmath-jmh/build.gradle @@ -4,11 +4,6 @@ plugins { id "me.champeau.gradle.jmh" version "0.4.7" } -repositories { - maven { url = 'http://dl.bintray.com/kotlin/kotlin-eap' } - mavenCentral() -} - dependencies { implementation project(':kmath-core') jmh 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'