Dimensions for JS

This commit is contained in:
Alexander Nozik 2020-04-27 15:43:03 +03:00
parent fbe7363cde
commit 30730f1051
7 changed files with 74 additions and 29 deletions

View File

@ -14,6 +14,7 @@ fun DMatrixContext<Double, RealField>.simple() {
m1.transpose() + m2 m1.transpose() + m2
} }
object D5 : Dimension { object D5 : Dimension {
override val dim: UInt = 5u override val dim: UInt = 5u
} }

View File

@ -7,8 +7,13 @@ description = "A proof of concept module for adding typ-safe dimensions to struc
kotlin.sourceSets { kotlin.sourceSets {
commonMain { commonMain {
dependencies { dependencies {
implementation(kotlin("reflect"))
api(project(":kmath-core")) api(project(":kmath-core"))
} }
} }
jvmMain{
dependencies{
api(kotlin("reflect"))
}
}
} }

View File

@ -1,37 +1,35 @@
package scientifik.kmath.dimensions package scientifik.kmath.dimensions
import kotlin.reflect.KClass
/** /**
* An interface which is not used in runtime. Designates a size of some structure. * An abstract class which is not used in runtime. Designates a size of some structure.
* All descendants should be singleton objects. * Could be replaced later by fully inline constructs
*/ */
interface Dimension { interface Dimension {
val dim: UInt val dim: UInt
companion object { companion object {
@Suppress("NOTHING_TO_INLINE")
inline fun of(dim: UInt): Dimension {
return when (dim) {
1u -> D1
2u -> D2
3u -> D3
else -> object : Dimension {
override val dim: UInt = dim
}
}
}
} }
} }
expect inline fun <reified D : Dimension> Dimension.Companion.dim(): UInt fun <D : Dimension> KClass<D>.dim(): UInt = Dimension.resolve(this).dim
expect fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D
expect fun Dimension.Companion.of(dim: UInt): Dimension
inline fun <reified D : Dimension> Dimension.Companion.dim(): UInt = D::class.dim()
object D1 : Dimension { object D1 : Dimension {
override val dim: UInt = 1u override val dim: UInt get() = 1U
} }
object D2 : Dimension { object D2 : Dimension {
override val dim: UInt = 2u override val dim: UInt get() = 2U
} }
object D3 : Dimension { object D3 : Dimension {
override val dim: UInt = 3u override val dim: UInt get() = 31U
} }

View File

@ -29,7 +29,7 @@ interface DMatrix<T, R : Dimension, C : Dimension> : Structure2D<T> {
/** /**
* The same as [coerce] but without dimension checks. Use with caution * The same as [coerce] but without dimension checks. Use with caution
*/ */
inline fun <T, reified R : Dimension, reified C : Dimension> coerceUnsafe(structure: Structure2D<T>): DMatrix<T, R, C> { fun <T, R : Dimension, C : Dimension> coerceUnsafe(structure: Structure2D<T>): DMatrix<T, R, C> {
return DMatrixWrapper(structure) return DMatrixWrapper(structure)
} }
} }
@ -57,7 +57,7 @@ interface DPoint<T, D : Dimension> : Point<T> {
return DPointWrapper(point) return DPointWrapper(point)
} }
inline fun <T, reified D : Dimension> coerceUnsafe(point: Point<T>): DPoint<T, D> { fun <T, D : Dimension> coerceUnsafe(point: Point<T>): DPoint<T, D> {
return DPointWrapper(point) return DPointWrapper(point)
} }
} }
@ -81,8 +81,15 @@ inline class DPointWrapper<T, D : Dimension>(val point: Point<T>) :
*/ */
inline class DMatrixContext<T : Any, Ri : Ring<T>>(val context: GenericMatrixContext<T, Ri>) { inline class DMatrixContext<T : Any, Ri : Ring<T>>(val context: GenericMatrixContext<T, Ri>) {
inline fun <reified R : Dimension, reified C : Dimension> Matrix<T>.coerce(): DMatrix<T, C, R> = inline fun <reified R : Dimension, reified C : Dimension> Matrix<T>.coerce(): DMatrix<T, R, C> {
DMatrix.coerceUnsafe(this) if (rowNum != Dimension.dim<R>().toInt()) {
error("Row number mismatch: expected ${Dimension.dim<R>()} but found $rowNum")
}
if (colNum != Dimension.dim<C>().toInt()) {
error("Column number mismatch: expected ${Dimension.dim<C>()} but found $colNum")
}
return DMatrix.coerceUnsafe(this)
}
/** /**
* Produce a matrix with this context and given dimensions * Produce a matrix with this context and given dimensions
@ -90,7 +97,7 @@ inline class DMatrixContext<T : Any, Ri : Ring<T>>(val context: GenericMatrixCon
inline fun <reified R : Dimension, reified C : Dimension> produce(noinline initializer: (i: Int, j: Int) -> T): DMatrix<T, R, C> { inline fun <reified R : Dimension, reified C : Dimension> produce(noinline initializer: (i: Int, j: Int) -> T): DMatrix<T, R, C> {
val rows = Dimension.dim<R>() val rows = Dimension.dim<R>()
val cols = Dimension.dim<C>() val cols = Dimension.dim<C>()
return context.produce(rows.toInt(), cols.toInt(), initializer).coerce() return context.produce(rows.toInt(), cols.toInt(), initializer).coerce<R,C>()
} }
inline fun <reified D : Dimension> point(noinline initializer: (Int) -> T): DPoint<T, D> { inline fun <reified D : Dimension> point(noinline initializer: (Int) -> T): DPoint<T, D> {

View File

@ -1,5 +1,8 @@
package scientifik.kmath.dimensions package scientifik.dimensions
import scientifik.kmath.dimensions.D2
import scientifik.kmath.dimensions.D3
import scientifik.kmath.dimensions.DMatrixContext
import kotlin.test.Test import kotlin.test.Test

View File

@ -1,5 +1,22 @@
package scientifik.kmath.dimensions package scientifik.kmath.dimensions
actual inline fun <reified D : Dimension> Dimension.Companion.dim(): UInt { import kotlin.reflect.KClass
TODO("KClass::objectInstance does not work")
private val dimensionMap = hashMapOf<UInt, Dimension>(
1u to D1,
2u to D2,
3u to D3
)
@Suppress("UNCHECKED_CAST")
actual fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D {
return dimensionMap.entries.find { it.value::class == type }?.value as? D ?: error("Can't resolve dimension $type")
}
actual fun Dimension.Companion.of(dim: UInt): Dimension {
return dimensionMap.getOrPut(dim) {
object : Dimension {
override val dim: UInt get() = dim
}
}
} }

View File

@ -1,4 +1,18 @@
package scientifik.kmath.dimensions package scientifik.kmath.dimensions
actual inline fun <reified D : Dimension> Dimension.Companion.dim(): UInt = import kotlin.reflect.KClass
D::class.objectInstance?.dim ?: error("Dimension object must be a singleton")
actual fun <D:Dimension> Dimension.Companion.resolve(type: KClass<D>): D{
return type.objectInstance ?: error("No object instance for dimension class")
}
actual fun Dimension.Companion.of(dim: UInt): Dimension{
return when(dim){
1u -> D1
2u -> D2
3u -> D3
else -> object : Dimension {
override val dim: UInt get() = dim
}
}
}