diff --git a/CHANGELOG.md b/CHANGELOG.md index f3fe37b6b..5d13a360f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`) - `Polynomial` secondary constructor made function. - Kotlin version: 1.3.72 -> 1.4.20-M1 +- `kmath-ast` doesn't depend on heavy `kotlin-reflect` library. ### Deprecated diff --git a/examples/src/main/kotlin/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/kscience/kmath/operations/ComplexDemo.kt index 3c97940a8..34b3c9981 100644 --- a/examples/src/main/kotlin/kscience/kmath/operations/ComplexDemo.kt +++ b/examples/src/main/kotlin/kscience/kmath/operations/ComplexDemo.kt @@ -5,15 +5,19 @@ import kscience.kmath.structures.NDField import kscience.kmath.structures.complex fun main() { + // 2d element val element = NDElement.complex(2, 2) { index: IntArray -> Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble()) } + println(element) - val compute = (NDField.complex(8)) { + // 1d element operation + val result = with(NDField.complex(8)) { val a = produce { (it) -> i * it - it.toDouble() } val b = 3 val c = Complex(1.0, 1.0) (a pow b) + c } + println(result) } diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index df876df10..a0afcdc4f 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -14,7 +14,6 @@ kotlin.sourceSets { implementation("org.ow2.asm:asm:8.0.1") implementation("org.ow2.asm:asm-commons:8.0.1") implementation("com.github.h0tk3y.betterParse:better-parse:0.4.0") - implementation(kotlin("reflect")) } } } diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt index 53425e7e3..2b6fa6247 100644 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt +++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt @@ -8,7 +8,6 @@ import kscience.kmath.ast.MST import kscience.kmath.ast.MstExpression import kscience.kmath.expressions.Expression import kscience.kmath.operations.Algebra -import kotlin.reflect.KClass /** * Compiles given MST to an Expression using AST compiler. @@ -18,7 +17,8 @@ import kotlin.reflect.KClass * @return the compiled expression. * @author Alexander Nozik */ -public fun MST.compileWith(type: KClass, algebra: Algebra): Expression { +@PublishedApi +internal fun MST.compileWith(type: Class, algebra: Algebra): Expression { fun AsmBuilder.visit(node: MST): Unit = when (node) { is MST.Symbolic -> { val symbol = try { @@ -61,11 +61,12 @@ public fun MST.compileWith(type: KClass, algebra: Algebra): Expr * * @author Alexander Nozik. */ -public inline fun Algebra.expression(mst: MST): Expression = mst.compileWith(T::class, this) +public inline fun Algebra.expression(mst: MST): Expression = + mst.compileWith(T::class.java, this) /** * Optimizes performance of an [MstExpression] using ASM codegen. * * @author Alexander Nozik. */ -public inline fun MstExpression.compile(): Expression = mst.compileWith(T::class, algebra) +public inline fun MstExpression.compile(): Expression = mst.compileWith(T::class.java, algebra) diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt index c64ca1d8f..06f02a94d 100644 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt @@ -10,7 +10,6 @@ import org.objectweb.asm.Opcodes.* import org.objectweb.asm.commons.InstructionAdapter import java.util.* import java.util.stream.Collectors -import kotlin.reflect.KClass /** * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. @@ -23,7 +22,7 @@ import kotlin.reflect.KClass * @author Iaroslav Postovalov */ internal class AsmBuilder internal constructor( - private val classOfT: KClass<*>, + private val classOfT: Class<*>, private val algebra: Algebra, private val className: String, private val invokeLabel0Visitor: AsmBuilder.() -> Unit @@ -43,7 +42,7 @@ internal class AsmBuilder internal constructor( /** * ASM Type for [algebra]. */ - private val tAlgebraType: Type = algebra::class.asm + private val tAlgebraType: Type = algebra.javaClass.asm /** * ASM type for [T]. @@ -55,16 +54,6 @@ internal class AsmBuilder internal constructor( */ private val classType: Type = Type.getObjectType(className.replace(oldChar = '.', newChar = '/'))!! - /** - * Index of `this` variable in invoke method of the built subclass. - */ - private val invokeThisVar: Int = 0 - - /** - * Index of `arguments` variable in invoke method of the built subclass. - */ - private val invokeArgumentsVar: Int = 1 - /** * List of constants to provide to the subclass. */ @@ -76,22 +65,22 @@ internal class AsmBuilder internal constructor( private lateinit var invokeMethodVisitor: InstructionAdapter /** - * State if this [AsmBuilder] needs to generate constants field. + * States whether this [AsmBuilder] needs to generate constants field. */ private var hasConstants: Boolean = true /** - * State if [T] a primitive type, so [AsmBuilder] may generate direct primitive calls. + * States whether [T] a primitive type, so [AsmBuilder] may generate direct primitive calls. */ internal var primitiveMode: Boolean = false /** - * Primitive type to apple for specific primitive calls. Use [OBJECT_TYPE], if not in [primitiveMode]. + * Primitive type to apply for specific primitive calls. Use [OBJECT_TYPE], if not in [primitiveMode]. */ internal var primitiveMask: Type = OBJECT_TYPE /** - * Boxed primitive type to apple for specific primitive calls. Use [OBJECT_TYPE], if not in [primitiveMode]. + * Boxed primitive type to apply for specific primitive calls. Use [OBJECT_TYPE], if not in [primitiveMode]. */ internal var primitiveMaskBoxed: Type = OBJECT_TYPE @@ -103,7 +92,7 @@ internal class AsmBuilder internal constructor( /** * Stack of useful objects types on stack expected by algebra calls. */ - internal val expectationStack: ArrayDeque = ArrayDeque(listOf(tType)) + internal val expectationStack: ArrayDeque = ArrayDeque(1).also { it.push(tType) } /** * The cache for instance built by this builder. @@ -361,7 +350,7 @@ internal class AsmBuilder internal constructor( * from it). */ private fun loadNumberConstant(value: Number, mustBeBoxed: Boolean) { - val boxed = value::class.asm + val boxed = value.javaClass.asm val primitive = BOXED_TO_PRIMITIVES[boxed] if (primitive != null) { @@ -475,17 +464,27 @@ internal class AsmBuilder internal constructor( internal fun loadStringConstant(string: String): Unit = invokeMethodVisitor.aconst(string) internal companion object { + /** + * Index of `this` variable in invoke method of the built subclass. + */ + private const val invokeThisVar: Int = 0 + + /** + * Index of `arguments` variable in invoke method of the built subclass. + */ + private const val invokeArgumentsVar: Int = 1 + /** * Maps JVM primitive numbers boxed types to their primitive ASM types. */ - private val SIGNATURE_LETTERS: Map, Type> by lazy { + private val SIGNATURE_LETTERS: Map, Type> by lazy { hashMapOf( - java.lang.Byte::class to Type.BYTE_TYPE, - java.lang.Short::class to Type.SHORT_TYPE, - java.lang.Integer::class to Type.INT_TYPE, - java.lang.Long::class to Type.LONG_TYPE, - java.lang.Float::class to Type.FLOAT_TYPE, - java.lang.Double::class to Type.DOUBLE_TYPE + java.lang.Byte::class.java to Type.BYTE_TYPE, + java.lang.Short::class.java to Type.SHORT_TYPE, + java.lang.Integer::class.java to Type.INT_TYPE, + java.lang.Long::class.java to Type.LONG_TYPE, + java.lang.Float::class.java to Type.FLOAT_TYPE, + java.lang.Double::class.java to Type.DOUBLE_TYPE ) } @@ -523,43 +522,43 @@ internal class AsmBuilder internal constructor( /** * Provides boxed number types values of which can be stored in JVM bytecode constant pool. */ - private val INLINABLE_NUMBERS: Set> by lazy { SIGNATURE_LETTERS.keys } + private val INLINABLE_NUMBERS: Set> by lazy { SIGNATURE_LETTERS.keys } /** * ASM type for [Expression]. */ - internal val EXPRESSION_TYPE: Type by lazy { Expression::class.asm } + internal val EXPRESSION_TYPE: Type by lazy { Type.getObjectType("kscience/kmath/expressions/Expression") } /** * ASM type for [java.lang.Number]. */ - internal val NUMBER_TYPE: Type by lazy { java.lang.Number::class.asm } + internal val NUMBER_TYPE: Type by lazy { Type.getObjectType("java/lang/Number") } /** * ASM type for [java.util.Map]. */ - internal val MAP_TYPE: Type by lazy { java.util.Map::class.asm } + internal val MAP_TYPE: Type by lazy { Type.getObjectType("java/util/Map") } /** * ASM type for [java.lang.Object]. */ - internal val OBJECT_TYPE: Type by lazy { java.lang.Object::class.asm } + internal val OBJECT_TYPE: Type by lazy { Type.getObjectType("java/lang/Object") } /** * ASM type for array of [java.lang.Object]. */ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "RemoveRedundantQualifierName") - internal val OBJECT_ARRAY_TYPE: Type by lazy { Array::class.asm } + internal val OBJECT_ARRAY_TYPE: Type by lazy { Type.getType("[Ljava/lang/Object;") } /** * ASM type for [Algebra]. */ - internal val ALGEBRA_TYPE: Type by lazy { Algebra::class.asm } + internal val ALGEBRA_TYPE: Type by lazy { Type.getObjectType("kscience/kmath/operations/Algebra") } /** * ASM type for [java.lang.String]. */ - internal val STRING_TYPE: Type by lazy { java.lang.String::class.asm } + internal val STRING_TYPE: Type by lazy { Type.getObjectType("java/lang/String") } /** * ASM type for MapIntrinsics. diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/codegenUtils.kt index 67fce40ac..ef9751502 100644 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/codegenUtils.kt +++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/codegenUtils.kt @@ -10,9 +10,9 @@ import org.objectweb.asm.* import org.objectweb.asm.Opcodes.INVOKEVIRTUAL import org.objectweb.asm.commons.InstructionAdapter import java.lang.reflect.Method +import java.util.* import kotlin.contracts.InvocationKind import kotlin.contracts.contract -import kotlin.reflect.KClass private val methodNameAdapters: Map, String> by lazy { hashMapOf( @@ -26,12 +26,12 @@ private val methodNameAdapters: Map, String> by lazy { } /** - * Returns ASM [Type] for given [KClass]. + * Returns ASM [Type] for given [Class]. * * @author Iaroslav Postovalov */ -internal val KClass<*>.asm: Type - get() = Type.getType(java) +internal inline val Class<*>.asm: Type + get() = Type.getType(this) /** * Returns singleton array with this value if the [predicate] is true, returns empty array otherwise. @@ -140,7 +140,7 @@ private fun AsmBuilder.buildExpectationStack( if (specific != null) mapTypes(specific, parameterTypes).reversed().forEach { expectationStack.push(it) } else - repeat(arity) { expectationStack.push(tType) } + expectationStack.addAll(Collections.nCopies(arity, tType)) return specific != null } @@ -169,7 +169,7 @@ private fun AsmBuilder.tryInvokeSpecific( val arity = parameterTypes.size val theName = methodNameAdapters[name to arity] ?: name val spec = findSpecific(context, theName, parameterTypes) ?: return false - val owner = context::class.asm + val owner = context.javaClass.asm invokeAlgebraOperation( owner = owner.internalName, diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt index 15e6625db..94cd3b321 100644 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt +++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt @@ -7,6 +7,7 @@ import com.github.h0tk3y.betterParse.grammar.parser import com.github.h0tk3y.betterParse.grammar.tryParseToEnd import com.github.h0tk3y.betterParse.lexer.Token import com.github.h0tk3y.betterParse.lexer.TokenMatch +import com.github.h0tk3y.betterParse.lexer.literalToken import com.github.h0tk3y.betterParse.lexer.regexToken import com.github.h0tk3y.betterParse.parser.ParseResult import com.github.h0tk3y.betterParse.parser.Parser @@ -23,14 +24,14 @@ public object ArithmeticsEvaluator : Grammar() { // TODO replace with "...".toRegex() when better-parse 0.4.1 is released private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?") private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*") - private val lpar: Token by regexToken("\\(") - private val rpar: Token by regexToken("\\)") - private val comma: Token by regexToken(",") - private val mul: Token by regexToken("\\*") - private val pow: Token by regexToken("\\^") - private val div: Token by regexToken("/") - private val minus: Token by regexToken("-") - private val plus: Token by regexToken("\\+") + private val lpar: Token by literalToken("(") + private val rpar: Token by literalToken(")") + private val comma: Token by literalToken(",") + private val mul: Token by literalToken("*") + private val pow: Token by literalToken("^") + private val div: Token by literalToken("/") + private val minus: Token by literalToken("-") + private val plus: Token by literalToken("+") private val ws: Token by regexToken("\\s+", ignore = true) private val number: Parser by num use { MST.Numeric(text.toDouble()) } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt index d410d304a..3c3b17d50 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt @@ -177,6 +177,11 @@ public data class Complex(val re: Double, val im: Double) : FieldElement { override val objectSize: Int get() = 16 diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt index 9756942b7..08160adf4 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt @@ -64,7 +64,7 @@ public interface NDStructure { public fun build( strides: Strides, bufferFactory: BufferFactory = Buffer.Companion::boxing, - initializer: (IntArray) -> T + initializer: (IntArray) -> T, ): BufferNDStructure = BufferNDStructure(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) }) @@ -73,40 +73,40 @@ public interface NDStructure { */ public inline fun auto( strides: Strides, - crossinline initializer: (IntArray) -> T + crossinline initializer: (IntArray) -> T, ): BufferNDStructure = BufferNDStructure(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) }) public inline fun auto( type: KClass, strides: Strides, - crossinline initializer: (IntArray) -> T + crossinline initializer: (IntArray) -> T, ): BufferNDStructure = BufferNDStructure(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) }) public fun build( shape: IntArray, bufferFactory: BufferFactory = Buffer.Companion::boxing, - initializer: (IntArray) -> T + initializer: (IntArray) -> T, ): BufferNDStructure = build(DefaultStrides(shape), bufferFactory, initializer) public inline fun auto( shape: IntArray, - crossinline initializer: (IntArray) -> T + crossinline initializer: (IntArray) -> T, ): BufferNDStructure = auto(DefaultStrides(shape), initializer) @JvmName("autoVarArg") public inline fun auto( vararg shape: Int, - crossinline initializer: (IntArray) -> T + crossinline initializer: (IntArray) -> T, ): BufferNDStructure = auto(DefaultStrides(shape), initializer) public inline fun auto( type: KClass, vararg shape: Int, - crossinline initializer: (IntArray) -> T + crossinline initializer: (IntArray) -> T, ): BufferNDStructure = auto(type, DefaultStrides(shape), initializer) } @@ -268,6 +268,22 @@ public abstract class NDBuffer : NDStructure { result = 31 * result + buffer.hashCode() return result } + + override fun toString(): String { + val bufferRepr: String = when (shape.size) { + 1 -> buffer.asSequence().joinToString(prefix = "[", postfix = "]", separator = ", ") + 2 -> (0 until shape[0]).joinToString(prefix = "[", postfix = "]", separator = ", ") { i -> + (0 until shape[1]).joinToString(prefix = "[", postfix = "]", separator = ", ") { j -> + val offset = strides.offset(intArrayOf(i, j)) + buffer[offset].toString() + } + } + else -> "..." + } + return "NDBuffer(shape=${shape.contentToString()}, buffer=$bufferRepr)" + } + + } /** @@ -275,7 +291,7 @@ public abstract class NDBuffer : NDStructure { */ public class BufferNDStructure( override val strides: Strides, - override val buffer: Buffer + override val buffer: Buffer, ) : NDBuffer() { init { if (strides.linearSize != buffer.size) { @@ -289,7 +305,7 @@ public class BufferNDStructure( */ public inline fun NDStructure.mapToBuffer( factory: BufferFactory = Buffer.Companion::auto, - crossinline transform: (T) -> R + crossinline transform: (T) -> R, ): BufferNDStructure { return if (this is BufferNDStructure) BufferNDStructure(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) }) @@ -304,7 +320,7 @@ public inline fun NDStructure.mapToBuffer( */ public class MutableBufferNDStructure( override val strides: Strides, - override val buffer: MutableBuffer + override val buffer: MutableBuffer, ) : NDBuffer(), MutableNDStructure { init { @@ -318,7 +334,7 @@ public class MutableBufferNDStructure( public inline fun NDStructure.combine( struct: NDStructure, - crossinline block: (T, T) -> T + crossinline block: (T, T) -> T, ): NDStructure { require(shape.contentEquals(struct.shape)) { "Shape mismatch in structure combination" } return NDStructure.auto(shape) { block(this[it], struct[it]) }