forked from kscience/kmath
Norm is a separate context
This commit is contained in:
parent
be18014d54
commit
68bd0ae0af
@ -1,7 +1,8 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.0'
|
||||
ext.kotlin_version = '1.3.10'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
@ -17,6 +18,11 @@ allprojects {
|
||||
|
||||
group = 'scientifik'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
if(file('artifactory.gradle').exists()){
|
||||
|
@ -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')
|
||||
|
@ -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<T : Any>(val rows: Int, val columns: Int, val field:
|
||||
result = 31 * result + field.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
infix fun <T : Any> Matrix<T>.dot(b: Matrix<T>): Matrix<T> = this.context.multiply(this, b)
|
||||
@ -191,11 +186,11 @@ interface Vector<T : Any> : SpaceElement<Vector<T>, VectorSpace<T>>, Buffer<T>,
|
||||
typealias NDFieldFactory<T> = (IntArray) -> NDField<T>
|
||||
|
||||
internal fun <T : Any> genericNDFieldFactory(field: Field<T>): NDFieldFactory<T> = { index -> GenericNDField(index, field) }
|
||||
internal val realNDFieldFactory: NDFieldFactory<Double> = { index -> GenericNDField(index, DoubleField) }
|
||||
internal val realNDFieldFactory: NDFieldFactory<Double> = { 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<T : Any>(
|
||||
rows: Int,
|
||||
@ -318,3 +313,8 @@ fun <T : Any> Vector<T>.toMatrix(): Matrix<T> {
|
||||
return Matrix.of(size, 1, context.field) { i, _ -> get(i) }
|
||||
}
|
||||
|
||||
object VectorL2Norm: Norm<Vector<out Number>, Double> {
|
||||
override fun norm(arg: Vector<out Number>): Double {
|
||||
return kotlin.math.sqrt(arg.sumByDouble { it.toDouble() })
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,20 @@ package scientifik.kmath.operations
|
||||
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* Advanced Number-like field that implements basic operations
|
||||
*/
|
||||
interface ExtendedField<N : Any> :
|
||||
Field<N>,
|
||||
TrigonometricOperations<N>,
|
||||
PowerOperations<N>,
|
||||
ExponentialOperations<N>
|
||||
|
||||
|
||||
/**
|
||||
* Field for real values
|
||||
*/
|
||||
object RealField : Field<Real>, TrigonometricOperations<Real>, PowerOperations<Real>, ExponentialOperations<Real> {
|
||||
object RealField : ExtendedField<Real>, Norm<Real, Real> {
|
||||
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<Real>, TrigonometricOperations<Real>, PowerOperations<R
|
||||
override fun multiply(a: Real, k: Double): Real = Real(a.value * k)
|
||||
override fun divide(a: Real, b: Real): Real = Real(a.value / b.value)
|
||||
|
||||
override fun sin(arg: Real): Real = Real(kotlin.math.sin(arg.value))
|
||||
override fun sin(arg: Real): Real = Real(kotlin.math.sin(arg.value))
|
||||
override fun cos(arg: Real): Real = Real(kotlin.math.cos(arg.value))
|
||||
|
||||
override fun power(arg: Real, pow: Double): Real = Real(arg.value.pow(pow))
|
||||
override fun power(arg: Real, pow: Double): Real = Real(arg.value.pow(pow))
|
||||
|
||||
override fun exp(arg: Real): Real = Real(kotlin.math.exp(arg.value))
|
||||
override fun exp(arg: Real): Real = Real(kotlin.math.exp(arg.value))
|
||||
|
||||
override fun ln(arg: Real): Real = Real(kotlin.math.ln(arg.value))
|
||||
override fun ln(arg: Real): Real = Real(kotlin.math.ln(arg.value))
|
||||
|
||||
override fun norm(arg: Real): Real = Real(kotlin.math.abs(arg.value))
|
||||
}
|
||||
|
||||
/**
|
||||
* Real field element wrapping double.
|
||||
*
|
||||
* TODO could be replaced by inline class in kotlin 1.3 if it would allow to avoid boxing
|
||||
* TODO inline does not work due to compiler bug. Waiting for fix
|
||||
*/
|
||||
data class Real(val value: Double) : Number(), FieldElement<Real, RealField> {
|
||||
/*
|
||||
* 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()
|
||||
class Real(val value: Double) : FieldElement<Real, RealField> {
|
||||
|
||||
//values are dynamically calculated to save memory
|
||||
override val self
|
||||
@ -53,19 +54,21 @@ data class Real(val value: Double) : Number(), FieldElement<Real, RealField> {
|
||||
/**
|
||||
* A field for double without boxing. Does not produce appropriate field element
|
||||
*/
|
||||
object DoubleField : Field<Double>, TrigonometricOperations<Double>, PowerOperations<Double>, ExponentialOperations<Double> {
|
||||
object DoubleField : ExtendedField<Double>, Norm<Double, Double> {
|
||||
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)
|
||||
}
|
@ -45,4 +45,10 @@ interface ExponentialOperations<T> {
|
||||
}
|
||||
|
||||
fun <T : MathElement<T, out ExponentialOperations<T>>> exp(arg: T): T = arg.context.exp(arg)
|
||||
fun <T : MathElement<T, out ExponentialOperations<T>>> ln(arg: T): T = arg.context.ln(arg)
|
||||
fun <T : MathElement<T, out ExponentialOperations<T>>> ln(arg: T): T = arg.context.ln(arg)
|
||||
|
||||
interface Norm<in T, out R> {
|
||||
fun norm(arg: T): R
|
||||
}
|
||||
|
||||
fun <T : MathElement<T, out Norm<T, R>>, R> norm(arg: T): R = arg.context.norm(arg)
|
@ -42,6 +42,7 @@ inline class ListBuffer<T>(private val list: MutableList<T>) : MutableBuffer<T>
|
||||
}
|
||||
|
||||
class ArrayBuffer<T>(private val array: Array<T>) : MutableBuffer<T> {
|
||||
//Can't inline because array invariant
|
||||
override val size: Int
|
||||
get() = array.size
|
||||
|
||||
@ -56,7 +57,7 @@ class ArrayBuffer<T>(private val array: Array<T>) : MutableBuffer<T> {
|
||||
override fun copy(): MutableBuffer<T> = ArrayBuffer(array.copyOf())
|
||||
}
|
||||
|
||||
class DoubleBuffer(private val array: DoubleArray) : MutableBuffer<Double> {
|
||||
inline class DoubleBuffer(private val array: DoubleArray) : MutableBuffer<Double> {
|
||||
override val size: Int
|
||||
get() = array.size
|
||||
|
||||
|
@ -0,0 +1,39 @@
|
||||
package scientifik.kmath.structures
|
||||
|
||||
import scientifik.kmath.operations.*
|
||||
|
||||
|
||||
/**
|
||||
* NDField that supports [ExtendedField] operations on its elements
|
||||
*/
|
||||
class ExtendedNDField<N: Any>(shape: IntArray, override val field: ExtendedField<N>) : NDField<N>(shape, field),
|
||||
TrigonometricOperations<NDArray<N>>,
|
||||
PowerOperations<NDArray<N>>,
|
||||
ExponentialOperations<NDArray<N>> {
|
||||
|
||||
override fun produceStructure(initializer: (IntArray) -> N): NDStructure<N> {
|
||||
return genericNdStructure(shape, initializer)
|
||||
}
|
||||
|
||||
override fun power(arg: NDArray<N>, pow: Double): NDArray<N> {
|
||||
return arg.transform { d -> with(field){power(d,pow)} }
|
||||
}
|
||||
|
||||
override fun exp(arg: NDArray<N>): NDArray<N> {
|
||||
return arg.transform { d -> with(field){exp(d)} }
|
||||
}
|
||||
|
||||
override fun ln(arg: NDArray<N>): NDArray<N> {
|
||||
return arg.transform { d -> with(field){ln(d)} }
|
||||
}
|
||||
|
||||
override fun sin(arg: NDArray<N>): NDArray<N> {
|
||||
return arg.transform { d -> with(field){sin(d)} }
|
||||
}
|
||||
|
||||
override fun cos(arg: NDArray<N>): NDArray<N> {
|
||||
return arg.transform { d -> with(field){cos(d)} }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<T>(val shape: IntArray, val field: Field<T>) : Field<NDArray<T>> {
|
||||
abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field<NDArray<T>> {
|
||||
|
||||
abstract fun produceStructure(initializer: (IntArray) -> T): NDStructure<T>
|
||||
|
||||
@ -173,7 +174,7 @@ object NDArrays {
|
||||
* Create a platform-optimized NDArray of doubles
|
||||
*/
|
||||
fun realNDArray(shape: IntArray, initializer: (IntArray) -> Double = { 0.0 }): NDArray<Double> {
|
||||
return RealNDField(shape).produce(initializer)
|
||||
return ExtendedNDField(shape, DoubleField).produce(initializer)
|
||||
}
|
||||
|
||||
fun real1DArray(dim: Int, initializer: (Int) -> Double = { _ -> 0.0 }): NDArray<Double> {
|
||||
@ -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<Double>.() -> NDArray<Double>) = ExtendedNDField(shape, DoubleField).run(block)
|
||||
|
||||
// /**
|
||||
// * Simple boxing NDField
|
||||
|
@ -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<Double>
|
||||
|
||||
|
||||
class RealNDField(shape: IntArray) : NDField<Double>(shape, DoubleField),
|
||||
TrigonometricOperations<RealNDArray>,
|
||||
PowerOperations<RealNDArray>,
|
||||
ExponentialOperations<RealNDArray> {
|
||||
|
||||
override fun produceStructure(initializer: (IntArray) -> Double): NDStructure<Double> {
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,8 @@ class RealFieldTest {
|
||||
@Test
|
||||
fun testSqrt() {
|
||||
val sqrt = with(RealField) {
|
||||
sqrt(25 * one)
|
||||
sqrt( 25 * one)
|
||||
}
|
||||
assertEquals(5.0, sqrt.toDouble())
|
||||
assertEquals(5.0, sqrt.value)
|
||||
}
|
||||
}
|
@ -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<NDArray<out Number>, Double> {
|
||||
override fun norm(arg: NDArray<out Number>): 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
kmath-io/build.gradle
Normal file
53
kmath-io/build.gradle
Normal file
@ -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 {
|
||||
// }
|
||||
}
|
||||
}
|
@ -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'
|
||||
|
@ -1,6 +1,7 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven { url = 'https://plugins.gradle.org/m2/' }
|
||||
}
|
||||
}
|
||||
@ -9,5 +10,7 @@ enableFeaturePreview('GRADLE_METADATA')
|
||||
|
||||
rootProject.name = 'kmath'
|
||||
include ':kmath-core'
|
||||
include ':kmath-io'
|
||||
|
||||
include ':kmath-jmh'
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user