From 3e7c9d8dce15fd5c17747aba953147e05c13c4f4 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 28 Nov 2020 13:33:05 +0700 Subject: [PATCH 01/55] Rework unary/binary operation API --- .../kotlin/kscience/kmath/ast/MST.kt | 19 ++- .../kotlin/kscience/kmath/ast/MstAlgebra.kt | 126 +++++++++--------- .../kscience/kmath/ast/MstExpression.kt | 6 +- .../kmath/asm/TestAsmSpecialization.kt | 15 +-- .../kotlin/kscience/kmath/ast/ParserTest.kt | 16 +-- .../FunctionalExpressionAlgebra.kt | 76 +++++------ .../kscience/kmath/linear/MatrixContext.kt | 9 +- .../kscience/kmath/operations/Algebra.kt | 72 +++++----- .../kmath/operations/NumberAlgebra.kt | 58 ++++---- 9 files changed, 194 insertions(+), 203 deletions(-) diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt index f312323b9..cc3d38f9c 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt @@ -55,24 +55,23 @@ public sealed class MST { public fun Algebra.evaluate(node: MST): T = when (node) { is MST.Numeric -> (this as? NumericAlgebra)?.number(node.value) ?: error("Numeric nodes are not supported by $this") + is MST.Symbolic -> symbol(node.value) - is MST.Unary -> unaryOperation(node.operation, evaluate(node.value)) + is MST.Unary -> unaryOperation(node.operation)(evaluate(node.value)) + is MST.Binary -> when { - this !is NumericAlgebra -> binaryOperation(node.operation, evaluate(node.left), evaluate(node.right)) + this !is NumericAlgebra -> binaryOperation(node.operation)(evaluate(node.left), evaluate(node.right)) node.left is MST.Numeric && node.right is MST.Numeric -> { - val number = RealField.binaryOperation( - node.operation, - node.left.value.toDouble(), - node.right.value.toDouble() - ) + val number = RealField + .binaryOperation(node.operation)(node.left.value.toDouble(), node.right.value.toDouble()) number(number) } - node.left is MST.Numeric -> leftSideNumberOperation(node.operation, node.left.value, evaluate(node.right)) - node.right is MST.Numeric -> rightSideNumberOperation(node.operation, evaluate(node.left), node.right.value) - else -> binaryOperation(node.operation, evaluate(node.left), evaluate(node.right)) + node.left is MST.Numeric -> leftSideNumberOperation(node.operation)(node.left.value, evaluate(node.right)) + node.right is MST.Numeric -> rightSideNumberOperation(node.operation)(evaluate(node.left), node.right.value) + else -> binaryOperation(node.operation)(evaluate(node.left), evaluate(node.right)) } } diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt index 6ee6ab9af..cea708342 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt @@ -6,115 +6,111 @@ import kscience.kmath.operations.* * [Algebra] over [MST] nodes. */ public object MstAlgebra : NumericAlgebra { - override fun number(value: Number): MST.Numeric = MST.Numeric(value) + public override fun number(value: Number): MST.Numeric = MST.Numeric(value) - override fun symbol(value: String): MST.Symbolic = MST.Symbolic(value) + public override fun symbol(value: String): MST.Symbolic = MST.Symbolic(value) - override fun unaryOperation(operation: String, arg: MST): MST.Unary = - MST.Unary(operation, arg) + public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = { arg -> MST.Unary(operation, arg) } - override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary = - MST.Binary(operation, left, right) + public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = + { left, right -> MST.Binary(operation, left, right) } } /** * [Space] over [MST] nodes. */ public object MstSpace : Space, NumericAlgebra { - override val zero: MST.Numeric by lazy { number(0.0) } + public override val zero: MST.Numeric by lazy { number(0.0) } - override fun number(value: Number): MST.Numeric = MstAlgebra.number(value) - override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value) - override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION, a, b) - override fun multiply(a: MST, k: Number): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION, a, number(k)) + public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value) + public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value) + override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) + override fun multiply(a: MST, k: Number): MST = binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k)) - override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary = - MstAlgebra.binaryOperation(operation, left, right) + override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST = + MstAlgebra.binaryOperation(operation) - override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstAlgebra.unaryOperation(operation, arg) + override fun unaryOperation(operation: String): (arg: MST) -> MST = MstAlgebra.unaryOperation(operation) } /** * [Ring] over [MST] nodes. */ public object MstRing : Ring, NumericAlgebra { - override val zero: MST.Numeric + override val zero: MST get() = MstSpace.zero + override val one: MST = number(1.0) - override val one: MST.Numeric by lazy { number(1.0) } + public override fun number(value: Number): MST = MstSpace.number(value) + public override fun symbol(value: String): MST = MstSpace.symbol(value) + public override fun add(a: MST, b: MST): MST = MstSpace.add(a, b) + public override fun multiply(a: MST, k: Number): MST = MstSpace.multiply(a, k) + public override fun multiply(a: MST, b: MST): MST = binaryOperation(RingOperations.TIMES_OPERATION)(a, b) - override fun number(value: Number): MST.Numeric = MstSpace.number(value) - override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value) - override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b) - override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k) - override fun multiply(a: MST, b: MST): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION, a, b) + public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST = + MstSpace.binaryOperation(operation) - override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary = - MstSpace.binaryOperation(operation, left, right) - - override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstSpace.unaryOperation(operation, arg) + public override fun unaryOperation(operation: String): (arg: MST) -> MST = MstAlgebra.unaryOperation(operation) } /** * [Field] over [MST] nodes. */ public object MstField : Field { - public override val zero: MST.Numeric + public override val zero: MST get() = MstRing.zero - public override val one: MST.Numeric + public override val one: MST get() = MstRing.one - public override fun symbol(value: String): MST.Symbolic = MstRing.symbol(value) - public override fun number(value: Number): MST.Numeric = MstRing.number(value) - public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) - public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k) - public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) - public override fun divide(a: MST, b: MST): MST.Binary = 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) - public override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary = - MstRing.binaryOperation(operation, left, right) + public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST = + MstRing.binaryOperation(operation) - override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstRing.unaryOperation(operation, arg) + public override fun unaryOperation(operation: String): (arg: MST) -> MST = MstRing.unaryOperation(operation) } /** * [ExtendedField] over [MST] nodes. */ public object MstExtendedField : ExtendedField { - override val zero: MST.Numeric + public override val zero: MST get() = MstField.zero - override val one: MST.Numeric + public override val one: MST get() = MstField.one - override fun symbol(value: String): MST.Symbolic = MstField.symbol(value) - override fun number(value: Number): MST.Numeric = MstField.number(value) - override fun sin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg) - override fun cos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.COS_OPERATION, arg) - override fun tan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.TAN_OPERATION, arg) - override fun asin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ASIN_OPERATION, arg) - override fun acos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ACOS_OPERATION, arg) - override fun atan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ATAN_OPERATION, arg) - override fun sinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.SINH_OPERATION, arg) - override fun cosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.COSH_OPERATION, arg) - override fun tanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.TANH_OPERATION, arg) - override fun asinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ASINH_OPERATION, arg) - override fun acosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ACOSH_OPERATION, arg) - override fun atanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ATANH_OPERATION, arg) - override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b) - override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k) - override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) - override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) + public override fun symbol(value: String): MST = MstField.symbol(value) + public override fun sin(arg: MST): MST = unaryOperation(TrigonometricOperations.SIN_OPERATION)(arg) + public override fun cos(arg: MST): MST = unaryOperation(TrigonometricOperations.COS_OPERATION)(arg) + public override fun tan(arg: MST): MST = unaryOperation(TrigonometricOperations.TAN_OPERATION)(arg) + public override fun asin(arg: MST): MST = unaryOperation(TrigonometricOperations.ASIN_OPERATION)(arg) + public override fun acos(arg: MST): MST = unaryOperation(TrigonometricOperations.ACOS_OPERATION)(arg) + public override fun atan(arg: MST): MST = unaryOperation(TrigonometricOperations.ATAN_OPERATION)(arg) + public override fun sinh(arg: MST): MST = unaryOperation(HyperbolicOperations.SINH_OPERATION)(arg) + public override fun cosh(arg: MST): MST = unaryOperation(HyperbolicOperations.COSH_OPERATION)(arg) + public override fun tanh(arg: MST): MST = unaryOperation(HyperbolicOperations.TANH_OPERATION)(arg) + public override fun asinh(arg: MST): MST = unaryOperation(HyperbolicOperations.ASINH_OPERATION)(arg) + public override fun acosh(arg: MST): MST = unaryOperation(HyperbolicOperations.ACOSH_OPERATION)(arg) + public override fun atanh(arg: MST): MST = unaryOperation(HyperbolicOperations.ATANH_OPERATION)(arg) + public override fun add(a: MST, b: MST): MST = MstField.add(a, b) + public override fun multiply(a: MST, k: Number): MST = MstField.multiply(a, k) + public override fun multiply(a: MST, b: MST): MST = MstField.multiply(a, b) + public override fun divide(a: MST, b: MST): MST = MstField.divide(a, b) + public override fun power(arg: MST, pow: Number): MST = binaryOperation(PowerOperations.POW_OPERATION)(arg, number(pow)) + public override fun exp(arg: MST): MST = unaryOperation(ExponentialOperations.EXP_OPERATION)(arg) + public override fun ln(arg: MST): MST = unaryOperation(ExponentialOperations.LN_OPERATION)(arg) - override fun power(arg: MST, pow: Number): MST.Binary = - binaryOperation(PowerOperations.POW_OPERATION, arg, number(pow)) + public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST = + MstField.binaryOperation(operation) - override fun exp(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.EXP_OPERATION, arg) - override fun ln(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.LN_OPERATION, arg) - - override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary = - MstField.binaryOperation(operation, left, right) - - override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstField.unaryOperation(operation, arg) + public override fun unaryOperation(operation: String): (arg: MST) -> MST = MstField.unaryOperation(operation) + override fun unaryOperation(operation: String, arg: MST): MST.Unary = + MST.Unary(operation, arg) } diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt index f68e3f5f8..8a99fd2f4 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt @@ -16,10 +16,8 @@ import kotlin.contracts.contract public class MstExpression>(public val algebra: A, public val mst: MST) : Expression { private inner class InnerAlgebra(val arguments: Map) : NumericAlgebra { override fun symbol(value: String): T = arguments[StringSymbol(value)] ?: algebra.symbol(value) - override fun unaryOperation(operation: String, arg: T): T = algebra.unaryOperation(operation, arg) - - override fun binaryOperation(operation: String, left: T, right: T): T = - algebra.binaryOperation(operation, left, right) + override fun unaryOperation(operation: String): (arg: T) -> T = algebra.unaryOperation(operation) + override fun binaryOperation(operation: String): (left: T, right: T) -> T = algebra.binaryOperation(operation) @Suppress("UNCHECKED_CAST") override fun number(value: Number): T = if (algebra is NumericAlgebra<*>) diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt index 8f8175acd..eb5a1c8f3 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt @@ -1,6 +1,5 @@ package kscience.kmath.asm -import kscience.kmath.asm.compile import kscience.kmath.ast.mstInField import kscience.kmath.expressions.invoke import kscience.kmath.operations.RealField @@ -10,44 +9,44 @@ import kotlin.test.assertEquals internal class TestAsmSpecialization { @Test fun testUnaryPlus() { - val expr = RealField.mstInField { unaryOperation("+", symbol("x")) }.compile() + val expr = RealField.mstInField { unaryOperation("+")(symbol("x")) }.compile() assertEquals(2.0, expr("x" to 2.0)) } @Test fun testUnaryMinus() { - val expr = RealField.mstInField { unaryOperation("-", symbol("x")) }.compile() + val expr = RealField.mstInField { unaryOperation("-")(symbol("x")) }.compile() assertEquals(-2.0, expr("x" to 2.0)) } @Test fun testAdd() { - val expr = RealField.mstInField { binaryOperation("+", symbol("x"), symbol("x")) }.compile() + val expr = RealField.mstInField { binaryOperation("+")(symbol("x"), symbol("x")) }.compile() assertEquals(4.0, expr("x" to 2.0)) } @Test fun testSine() { - val expr = RealField.mstInField { unaryOperation("sin", symbol("x")) }.compile() + val expr = RealField.mstInField { unaryOperation("sin")(symbol("x")) }.compile() assertEquals(0.0, expr("x" to 0.0)) } @Test fun testMinus() { - val expr = RealField.mstInField { binaryOperation("-", symbol("x"), symbol("x")) }.compile() + val expr = RealField.mstInField { binaryOperation("-")(symbol("x"), symbol("x")) }.compile() assertEquals(0.0, expr("x" to 2.0)) } @Test fun testDivide() { - val expr = RealField.mstInField { binaryOperation("/", symbol("x"), symbol("x")) }.compile() + val expr = RealField.mstInField { binaryOperation("/")(symbol("x"), symbol("x")) }.compile() assertEquals(1.0, expr("x" to 2.0)) } @Test fun testPower() { val expr = RealField - .mstInField { binaryOperation("power", symbol("x"), number(2)) } + .mstInField { binaryOperation("power")(symbol("x"), number(2)) } .compile() assertEquals(4.0, expr("x" to 2.0)) diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt index 2dc24597e..e2029ce19 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt @@ -1,8 +1,5 @@ package kscience.kmath.ast -import kscience.kmath.ast.evaluate -import kscience.kmath.ast.mstInField -import kscience.kmath.ast.parseMath import kscience.kmath.expressions.invoke import kscience.kmath.operations.Algebra import kscience.kmath.operations.Complex @@ -45,12 +42,15 @@ internal class ParserTest { val magicalAlgebra = object : Algebra { override fun symbol(value: String): String = value - override fun unaryOperation(operation: String, arg: String): String = throw NotImplementedError() - - override fun binaryOperation(operation: String, left: String, right: String): String = when (operation) { - "magic" -> "$left ★ $right" - else -> throw NotImplementedError() + override fun unaryOperation(operation: String): (arg: String) -> String { + throw NotImplementedError() } + + override fun binaryOperation(operation: String): (left: String, right: String) -> String = + when (operation) { + "magic" -> { left, right -> "$left ★ $right" } + else -> throw NotImplementedError() + } } val mst = "magic(a, b)".parseMath() diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 0630e8e4b..e2413dea8 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -7,9 +7,8 @@ import kscience.kmath.operations.* * * @param algebra The algebra to provide for Expressions built. */ -public abstract class FunctionalExpressionAlgebra>( - public val algebra: A, -) : ExpressionAlgebra> { +public abstract class FunctionalExpressionAlgebra>(public val algebra: A) : + ExpressionAlgebra> { /** * Builds an Expression of constant expression which does not depend on arguments. */ @@ -25,19 +24,18 @@ public abstract class FunctionalExpressionAlgebra>( /** * Builds an Expression of dynamic call of binary operation [operation] on [left] and [right]. */ - public override fun binaryOperation( - operation: String, - left: Expression, - right: Expression, - ): Expression = Expression { arguments -> - algebra.binaryOperation(operation, left.invoke(arguments), right.invoke(arguments)) - } + public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = + { left, right -> + Expression { arguments -> + algebra.binaryOperation(operation)(left.invoke(arguments), right.invoke(arguments)) + } + } /** * Builds an Expression of dynamic call of unary operation with name [operation] on [arg]. */ - public override fun unaryOperation(operation: String, arg: Expression): Expression = Expression { arguments -> - algebra.unaryOperation(operation, arg.invoke(arguments)) + public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = { arg -> + Expression { arguments -> algebra.unaryOperation(operation)(arg.invoke(arguments)) } } } @@ -52,7 +50,7 @@ public open class FunctionalExpressionSpace>(algebra: A) : * Builds an Expression of addition of two another expressions. */ public override fun add(a: Expression, b: Expression): Expression = - binaryOperation(SpaceOperations.PLUS_OPERATION, a, b) + binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) /** * Builds an Expression of multiplication of expression by number. @@ -66,11 +64,11 @@ 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 - public override fun unaryOperation(operation: String, arg: Expression): Expression = - super.unaryOperation(operation, arg) + public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = + super.unaryOperation(operation) - public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = - super.binaryOperation(operation, left, right) + public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = + super.binaryOperation(operation) } public open class FunctionalExpressionRing(algebra: A) : FunctionalExpressionSpace(algebra), @@ -82,16 +80,16 @@ public open class FunctionalExpressionRing(algebra: A) : FunctionalExpress * Builds an Expression of multiplication of two expressions. */ public override fun multiply(a: Expression, b: Expression): Expression = - binaryOperation(RingOperations.TIMES_OPERATION, a, b) + 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 - public override fun unaryOperation(operation: String, arg: Expression): Expression = - super.unaryOperation(operation, arg) + public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = + super.unaryOperation(operation) - public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = - super.binaryOperation(operation, left, right) + public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = + super.binaryOperation(operation) } public open class FunctionalExpressionField(algebra: A) : @@ -101,49 +99,49 @@ public open class FunctionalExpressionField(algebra: A) : * Builds an Expression of division an expression by another one. */ public override fun divide(a: Expression, b: Expression): Expression = - binaryOperation(FieldOperations.DIV_OPERATION, a, b) + 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 - public override fun unaryOperation(operation: String, arg: Expression): Expression = - super.unaryOperation(operation, arg) + public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = + super.unaryOperation(operation) - public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = - super.binaryOperation(operation, left, right) + public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = + super.binaryOperation(operation) } public open class FunctionalExpressionExtendedField(algebra: A) : FunctionalExpressionField(algebra), ExtendedField> where A : ExtendedField, A : NumericAlgebra { public override fun sin(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.SIN_OPERATION, arg) + unaryOperation(TrigonometricOperations.SIN_OPERATION)(arg) public override fun cos(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.COS_OPERATION, arg) + unaryOperation(TrigonometricOperations.COS_OPERATION)(arg) public override fun asin(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.ASIN_OPERATION, arg) + unaryOperation(TrigonometricOperations.ASIN_OPERATION)(arg) public override fun acos(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.ACOS_OPERATION, arg) + unaryOperation(TrigonometricOperations.ACOS_OPERATION)(arg) public override fun atan(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.ATAN_OPERATION, arg) + unaryOperation(TrigonometricOperations.ATAN_OPERATION)(arg) public override fun power(arg: Expression, pow: Number): Expression = - binaryOperation(PowerOperations.POW_OPERATION, arg, number(pow)) + binaryOperation(PowerOperations.POW_OPERATION)(arg, number(pow)) public override fun exp(arg: Expression): Expression = - unaryOperation(ExponentialOperations.EXP_OPERATION, arg) + unaryOperation(ExponentialOperations.EXP_OPERATION)(arg) - public override fun ln(arg: Expression): Expression = unaryOperation(ExponentialOperations.LN_OPERATION, arg) + public override fun ln(arg: Expression): Expression = unaryOperation(ExponentialOperations.LN_OPERATION)(arg) - public override fun unaryOperation(operation: String, arg: Expression): Expression = - super.unaryOperation(operation, arg) + public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = + super.unaryOperation(operation) - public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression = - super.binaryOperation(operation, left, right) + public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = + super.binaryOperation(operation) } public inline fun > A.expressionInSpace(block: FunctionalExpressionSpace.() -> Expression): Expression = diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt index f4dbce89a..174f62c12 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt @@ -18,10 +18,11 @@ public interface MatrixContext : SpaceOperations> { */ public fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): Matrix - public override fun binaryOperation(operation: String, left: Matrix, right: Matrix): Matrix = when (operation) { - "dot" -> left dot right - else -> super.binaryOperation(operation, left, right) - } + public override fun binaryOperation(operation: String): (left: Matrix, right: Matrix) -> Matrix = + when (operation) { + "dot" -> { left, right -> left dot right } + else -> super.binaryOperation(operation) + } /** * Computes the dot product of this matrix and another one. diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index 12a45615a..19ca1a4cc 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -13,19 +13,19 @@ public annotation class KMathContext */ public interface Algebra { /** - * Wrap raw string or variable + * Wraps raw string or variable. */ public fun symbol(value: String): T = error("Wrapping of '$value' is not supported in $this") /** - * Dynamic call of unary operation with name [operation] on [arg] + * Dynamically dispatches an unary operation with name [operation]. */ - public fun unaryOperation(operation: String, arg: T): T + public fun unaryOperation(operation: String): (arg: T) -> T /** - * Dynamic call of binary operation [operation] on [left] and [right] + * Dynamically dispatches a binary operation with name [operation]. */ - public fun binaryOperation(operation: String, left: T, right: T): T + public fun binaryOperation(operation: String): (left: T, right: T) -> T } /** @@ -40,16 +40,28 @@ public interface NumericAlgebra : Algebra { public fun number(value: Number): T /** - * Dynamic call of binary operation [operation] on [left] and [right] where left element is [Number]. + * Dynamically dispatches a binary operation with name [operation] where the left argument is [Number]. */ - public fun leftSideNumberOperation(operation: String, left: Number, right: T): T = - binaryOperation(operation, number(left), right) + public fun leftSideNumberOperation(operation: String): (left: Number, right: T) -> T = + { l, r -> binaryOperation(operation)(number(l), r) } + +// /** +// * Dynamically calls a binary operation with name [operation] where the left argument is [Number]. +// */ +// public fun leftSideNumberOperation(operation: String, left: Number, right: T): T = +// leftSideNumberOperation(operation)(left, right) /** - * Dynamic call of binary operation [operation] on [left] and [right] where right element is [Number]. + * Dynamically dispatches a binary operation with name [operation] where the right argument is [Number]. */ - public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = - leftSideNumberOperation(operation, right, left) + public fun rightSideNumberOperation(operation: String): (left: T, right: Number) -> T = + { l, r -> binaryOperation(operation)(l, number(r)) } + +// /** +// * Dynamically calls a binary operation with name [operation] where the right argument is [Number]. +// */ +// public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = +// rightSideNumberOperation(operation)(left, right) } /** @@ -146,15 +158,15 @@ public interface SpaceOperations : Algebra { */ public operator fun Number.times(b: T): T = b * this - override fun unaryOperation(operation: String, arg: T): T = when (operation) { - PLUS_OPERATION -> arg - MINUS_OPERATION -> -arg + override fun unaryOperation(operation: String): (arg: T) -> T = when (operation) { + PLUS_OPERATION -> { arg -> arg } + MINUS_OPERATION -> { arg -> -arg } else -> error("Unary operation $operation not defined in $this") } - override fun binaryOperation(operation: String, left: T, right: T): T = when (operation) { - PLUS_OPERATION -> add(left, right) - MINUS_OPERATION -> left - right + override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { + PLUS_OPERATION -> ::add + MINUS_OPERATION -> { left, right -> left - right } else -> error("Binary operation $operation not defined in $this") } @@ -207,9 +219,9 @@ public interface RingOperations : SpaceOperations { */ public operator fun T.times(b: T): T = multiply(this, b) - override fun binaryOperation(operation: String, left: T, right: T): T = when (operation) { - TIMES_OPERATION -> multiply(left, right) - else -> super.binaryOperation(operation, left, right) + override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { + TIMES_OPERATION -> ::multiply + else -> super.binaryOperation(operation) } public companion object { @@ -234,20 +246,6 @@ public interface Ring : Space, RingOperations, NumericAlgebra { override fun number(value: Number): T = one * value.toDouble() - override fun leftSideNumberOperation(operation: String, left: Number, right: T): T = when (operation) { - SpaceOperations.PLUS_OPERATION -> left + right - SpaceOperations.MINUS_OPERATION -> left - right - RingOperations.TIMES_OPERATION -> left * right - else -> super.leftSideNumberOperation(operation, left, right) - } - - override fun rightSideNumberOperation(operation: String, left: T, right: Number): T = when (operation) { - SpaceOperations.PLUS_OPERATION -> left + right - SpaceOperations.MINUS_OPERATION -> left - right - RingOperations.TIMES_OPERATION -> left * right - else -> super.rightSideNumberOperation(operation, left, right) - } - /** * Addition of element and scalar. * @@ -308,9 +306,9 @@ public interface FieldOperations : RingOperations { */ public operator fun T.div(b: T): T = divide(this, b) - override fun binaryOperation(operation: String, left: T, right: T): T = when (operation) { - DIV_OPERATION -> divide(left, right) - else -> super.binaryOperation(operation, left, right) + override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { + DIV_OPERATION -> ::divide + else -> super.binaryOperation(operation) } public companion object { diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt index a2b33a0c4..611222d34 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt @@ -15,23 +15,23 @@ public interface ExtendedFieldOperations : public override fun tan(arg: T): T = sin(arg) / cos(arg) public override fun tanh(arg: T): T = sinh(arg) / cosh(arg) - public override fun unaryOperation(operation: String, arg: T): T = when (operation) { - TrigonometricOperations.COS_OPERATION -> cos(arg) - TrigonometricOperations.SIN_OPERATION -> sin(arg) - TrigonometricOperations.TAN_OPERATION -> tan(arg) - TrigonometricOperations.ACOS_OPERATION -> acos(arg) - TrigonometricOperations.ASIN_OPERATION -> asin(arg) - TrigonometricOperations.ATAN_OPERATION -> atan(arg) - HyperbolicOperations.COSH_OPERATION -> cosh(arg) - HyperbolicOperations.SINH_OPERATION -> sinh(arg) - HyperbolicOperations.TANH_OPERATION -> tanh(arg) - HyperbolicOperations.ACOSH_OPERATION -> acosh(arg) - HyperbolicOperations.ASINH_OPERATION -> asinh(arg) - HyperbolicOperations.ATANH_OPERATION -> atanh(arg) - PowerOperations.SQRT_OPERATION -> sqrt(arg) - ExponentialOperations.EXP_OPERATION -> exp(arg) - ExponentialOperations.LN_OPERATION -> ln(arg) - else -> super.unaryOperation(operation, arg) + public override fun unaryOperation(operation: String): (arg: T) -> T = when (operation) { + TrigonometricOperations.COS_OPERATION -> ::cos + TrigonometricOperations.SIN_OPERATION -> ::sin + TrigonometricOperations.TAN_OPERATION -> ::tan + TrigonometricOperations.ACOS_OPERATION -> ::acos + TrigonometricOperations.ASIN_OPERATION -> ::asin + TrigonometricOperations.ATAN_OPERATION -> ::atan + HyperbolicOperations.COSH_OPERATION -> ::cosh + HyperbolicOperations.SINH_OPERATION -> ::sinh + HyperbolicOperations.TANH_OPERATION -> ::tanh + HyperbolicOperations.ACOSH_OPERATION -> ::acosh + HyperbolicOperations.ASINH_OPERATION -> ::asinh + HyperbolicOperations.ATANH_OPERATION -> ::atanh + PowerOperations.SQRT_OPERATION -> ::sqrt + ExponentialOperations.EXP_OPERATION -> ::exp + ExponentialOperations.LN_OPERATION -> ::ln + else -> super.unaryOperation(operation) } } @@ -46,10 +46,11 @@ public interface ExtendedField : ExtendedFieldOperations, Field { public override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) public override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2 - public override fun rightSideNumberOperation(operation: String, left: T, right: Number): T = when (operation) { - PowerOperations.POW_OPERATION -> power(left, right) - else -> super.rightSideNumberOperation(operation, left, right) - } + public override fun rightSideNumberOperation(operation: String): (left: T, right: Number) -> T = + when (operation) { + PowerOperations.POW_OPERATION -> ::power + else -> super.rightSideNumberOperation(operation) + } } /** @@ -80,10 +81,11 @@ public object RealField : ExtendedField, Norm { public override val one: Double get() = 1.0 - public override fun binaryOperation(operation: String, left: Double, right: Double): Double = when (operation) { - PowerOperations.POW_OPERATION -> left pow right - else -> super.binaryOperation(operation, left, right) - } + public override fun binaryOperation(operation: String): (left: Double, right: Double) -> Double = + when (operation) { + PowerOperations.POW_OPERATION -> ::power + else -> super.binaryOperation(operation) + } public override inline fun add(a: Double, b: Double): Double = a + b public override inline fun multiply(a: Double, k: Number): Double = a * k.toDouble() @@ -130,9 +132,9 @@ public object FloatField : ExtendedField, Norm { public override val one: Float get() = 1.0f - public override fun binaryOperation(operation: String, left: Float, right: Float): Float = when (operation) { - PowerOperations.POW_OPERATION -> left pow right - else -> super.binaryOperation(operation, left, right) + public override fun binaryOperation(operation: String): (left: Float, right: Float) -> Float = when (operation) { + PowerOperations.POW_OPERATION -> ::power + else -> super.binaryOperation(operation) } public override inline fun add(a: Float, b: Float): Float = a + b From e447a15304f2c1b7df9ad00c48a721db9f92edc6 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 28 Nov 2020 13:42:18 +0700 Subject: [PATCH 02/55] Make MstAlgebra operations return specific types --- .../kotlin/kscience/kmath/ast/MstAlgebra.kt | 101 +++++++++--------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt index cea708342..44a7f20b9 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt @@ -7,10 +7,10 @@ import kscience.kmath.operations.* */ public object MstAlgebra : NumericAlgebra { public override fun number(value: Number): MST.Numeric = MST.Numeric(value) - public override fun symbol(value: String): MST.Symbolic = MST.Symbolic(value) - public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = { arg -> MST.Unary(operation, arg) } + public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = + { arg -> MST.Unary(operation, arg) } public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = { left, right -> MST.Binary(operation, left, right) } @@ -25,92 +25,95 @@ public object MstSpace : Space, NumericAlgebra { public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value) public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value) override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) - override fun multiply(a: MST, k: Number): MST = binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k)) + override fun multiply(a: MST, k: Number): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k)) - override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST = + override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstAlgebra.binaryOperation(operation) - override fun unaryOperation(operation: String): (arg: MST) -> MST = MstAlgebra.unaryOperation(operation) + override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = MstAlgebra.unaryOperation(operation) } /** * [Ring] over [MST] nodes. */ public object MstRing : Ring, NumericAlgebra { - override val zero: MST + override val zero: MST.Numeric get() = MstSpace.zero - override val one: MST = number(1.0) - public override fun number(value: Number): MST = MstSpace.number(value) - public override fun symbol(value: String): MST = MstSpace.symbol(value) - public override fun add(a: MST, b: MST): MST = MstSpace.add(a, b) - public override fun multiply(a: MST, k: Number): MST = MstSpace.multiply(a, k) - public override fun multiply(a: MST, b: MST): MST = binaryOperation(RingOperations.TIMES_OPERATION)(a, b) + override val one: MST.Numeric by lazy { number(1.0) } - public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST = + public override fun number(value: Number): MST.Numeric = MstSpace.number(value) + public override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value) + public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b) + public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k) + public override fun multiply(a: MST, b: MST): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, b) + + public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstSpace.binaryOperation(operation) - public override fun unaryOperation(operation: String): (arg: MST) -> MST = MstAlgebra.unaryOperation(operation) + public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = + MstAlgebra.unaryOperation(operation) } /** * [Field] over [MST] nodes. */ public object MstField : Field { - public override val zero: MST + public override val zero: MST.Numeric get() = MstRing.zero - public override val one: MST + public override val one: MST.Numeric get() = MstRing.one - 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) + public override fun symbol(value: String): MST.Symbolic = MstRing.symbol(value) + public override fun number(value: Number): MST.Numeric = MstRing.number(value) + public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) + public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k) + public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) + public override fun divide(a: MST, b: MST): MST.Binary = binaryOperation(FieldOperations.DIV_OPERATION)(a, b) - public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST = + public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperation(operation) - public override fun unaryOperation(operation: String): (arg: MST) -> MST = MstRing.unaryOperation(operation) + public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = MstRing.unaryOperation(operation) } /** * [ExtendedField] over [MST] nodes. */ public object MstExtendedField : ExtendedField { - public override val zero: MST + public override val zero: MST.Numeric get() = MstField.zero - public override val one: MST + public override val one: MST.Numeric get() = MstField.one public override fun symbol(value: String): MST = MstField.symbol(value) - public override fun sin(arg: MST): MST = unaryOperation(TrigonometricOperations.SIN_OPERATION)(arg) - public override fun cos(arg: MST): MST = unaryOperation(TrigonometricOperations.COS_OPERATION)(arg) - public override fun tan(arg: MST): MST = unaryOperation(TrigonometricOperations.TAN_OPERATION)(arg) - public override fun asin(arg: MST): MST = unaryOperation(TrigonometricOperations.ASIN_OPERATION)(arg) - public override fun acos(arg: MST): MST = unaryOperation(TrigonometricOperations.ACOS_OPERATION)(arg) - public override fun atan(arg: MST): MST = unaryOperation(TrigonometricOperations.ATAN_OPERATION)(arg) - public override fun sinh(arg: MST): MST = unaryOperation(HyperbolicOperations.SINH_OPERATION)(arg) - public override fun cosh(arg: MST): MST = unaryOperation(HyperbolicOperations.COSH_OPERATION)(arg) - public override fun tanh(arg: MST): MST = unaryOperation(HyperbolicOperations.TANH_OPERATION)(arg) - public override fun asinh(arg: MST): MST = unaryOperation(HyperbolicOperations.ASINH_OPERATION)(arg) - public override fun acosh(arg: MST): MST = unaryOperation(HyperbolicOperations.ACOSH_OPERATION)(arg) - public override fun atanh(arg: MST): MST = unaryOperation(HyperbolicOperations.ATANH_OPERATION)(arg) - public override fun add(a: MST, b: MST): MST = MstField.add(a, b) - public override fun multiply(a: MST, k: Number): MST = MstField.multiply(a, k) - public override fun multiply(a: MST, b: MST): MST = MstField.multiply(a, b) - public override fun divide(a: MST, b: MST): MST = MstField.divide(a, b) - public override fun power(arg: MST, pow: Number): MST = binaryOperation(PowerOperations.POW_OPERATION)(arg, number(pow)) - public override fun exp(arg: MST): MST = unaryOperation(ExponentialOperations.EXP_OPERATION)(arg) - public override fun ln(arg: MST): MST = unaryOperation(ExponentialOperations.LN_OPERATION)(arg) + public override fun sin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.SIN_OPERATION)(arg) + public override fun cos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.COS_OPERATION)(arg) + public override fun tan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.TAN_OPERATION)(arg) + public override fun asin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ASIN_OPERATION)(arg) + public override fun acos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ACOS_OPERATION)(arg) + public override fun atan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ATAN_OPERATION)(arg) + public override fun sinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.SINH_OPERATION)(arg) + public override fun cosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.COSH_OPERATION)(arg) + public override fun tanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.TANH_OPERATION)(arg) + public override fun asinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ASINH_OPERATION)(arg) + public override fun acosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ACOSH_OPERATION)(arg) + public override fun atanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ATANH_OPERATION)(arg) + public override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b) + public override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k) + public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) + public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) - public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST = + public override fun power(arg: MST, pow: Number): MST.Binary = + binaryOperation(PowerOperations.POW_OPERATION)(arg, number(pow)) + + public override fun exp(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.EXP_OPERATION)(arg) + public override fun ln(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.LN_OPERATION)(arg) + + public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstField.binaryOperation(operation) - public override fun unaryOperation(operation: String): (arg: MST) -> MST = MstField.unaryOperation(operation) - override fun unaryOperation(operation: String, arg: MST): MST.Unary = - MST.Unary(operation, arg) + public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = MstField.unaryOperation(operation) } From e62cf4fc6586643f6a5adddd2e1f25deb1b756cc Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 8 Dec 2020 14:42:42 +0700 Subject: [PATCH 03/55] Rewrite ASM codegen to use curried operators, fix bugs, update benchmarks --- .../ast/ExpressionsInterpretersBenchmark.kt | 49 +-- .../kmath/structures/ArrayBenchmark.kt | 8 +- .../kmath/structures/ViktorBenchmark.kt | 2 +- .../kotlin/kscience/kmath/ast/MST.kt | 3 +- .../kotlin/kscience/kmath/ast/MstAlgebra.kt | 15 +- .../kscience/kmath/ast/MstExpression.kt | 7 +- .../jvmMain/kotlin/kscience/kmath/asm/asm.kt | 49 +-- .../kscience/kmath/asm/internal/AsmBuilder.kt | 300 ++++-------------- .../kscience/kmath/asm/internal/MstType.kt | 20 -- .../kmath/asm/internal/codegenUtils.kt | 120 ------- .../kscience/kmath/asm/TestAsmAlgebras.kt | 36 +-- .../kscience/kmath/asm/TestAsmExpressions.kt | 12 +- .../kmath/asm/TestAsmSpecialization.kt | 2 +- .../kscience/kmath/asm/TestAsmVariables.kt | 2 +- .../kscience/kmath/operations/Algebra.kt | 10 +- .../kmath/operations/NumberAlgebra.kt | 2 +- 16 files changed, 158 insertions(+), 479 deletions(-) rename examples/src/{main => benchmarks}/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt (66%) delete mode 100644 kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/MstType.kt diff --git a/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt similarity index 66% rename from examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt rename to examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt index a4806ed68..6acaca84d 100644 --- a/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt @@ -4,13 +4,19 @@ import kscience.kmath.asm.compile import kscience.kmath.expressions.Expression import kscience.kmath.expressions.expressionInField import kscience.kmath.expressions.invoke +import kscience.kmath.expressions.symbol import kscience.kmath.operations.Field import kscience.kmath.operations.RealField +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State import kotlin.random.Random -import kotlin.system.measureTimeMillis +@State(Scope.Benchmark) internal class ExpressionsInterpretersBenchmark { private val algebra: Field = RealField + + @Benchmark fun functionalExpression() { val expr = algebra.expressionInField { symbol("x") * const(2.0) + const(2.0) / symbol("x") - const(16.0) @@ -19,6 +25,7 @@ internal class ExpressionsInterpretersBenchmark { invokeAndSum(expr) } + @Benchmark fun mstExpression() { val expr = algebra.mstInField { symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0) @@ -27,6 +34,7 @@ internal class ExpressionsInterpretersBenchmark { invokeAndSum(expr) } + @Benchmark fun asmExpression() { val expr = algebra.mstInField { symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0) @@ -35,6 +43,13 @@ internal class ExpressionsInterpretersBenchmark { invokeAndSum(expr) } + @Benchmark + fun rawExpression() { + val x by symbol + val expr = Expression { args -> args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 } + invokeAndSum(expr) + } + private fun invokeAndSum(expr: Expression) { val random = Random(0) var sum = 0.0 @@ -46,35 +61,3 @@ internal class ExpressionsInterpretersBenchmark { println(sum) } } - -/** - * This benchmark compares basically evaluation of simple function with MstExpression interpreter, ASM backend and - * core FunctionalExpressions API. - * - * The expected rating is: - * - * 1. ASM. - * 2. MST. - * 3. FE. - */ -fun main() { - val benchmark = ExpressionsInterpretersBenchmark() - - val fe = measureTimeMillis { - benchmark.functionalExpression() - } - - println("fe=$fe") - - val mst = measureTimeMillis { - benchmark.mstExpression() - } - - println("mst=$mst") - - val asm = measureTimeMillis { - benchmark.asmExpression() - } - - println("asm=$asm") -} diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/structures/ArrayBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/structures/ArrayBenchmark.kt index a91d02253..f7e0d05c6 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/structures/ArrayBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/structures/ArrayBenchmark.kt @@ -16,17 +16,13 @@ internal class ArrayBenchmark { @Benchmark fun benchmarkBufferRead() { var res = 0 - for (i in 1..size) res += arrayBuffer.get( - size - i - ) + for (i in 1..size) res += arrayBuffer[size - i] } @Benchmark fun nativeBufferRead() { var res = 0 - for (i in 1..size) res += nativeBuffer.get( - size - i - ) + for (i in 1..size) res += nativeBuffer[size - i] } companion object { diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/structures/ViktorBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/structures/ViktorBenchmark.kt index 464925ca0..df35b0b78 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/structures/ViktorBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/structures/ViktorBenchmark.kt @@ -36,7 +36,7 @@ internal class ViktorBenchmark { @Benchmark fun rawViktor() { - val one = F64Array.full(init = 1.0, shape = *intArrayOf(dim, dim)) + val one = F64Array.full(init = 1.0, shape = intArrayOf(dim, dim)) var res = one repeat(n) { res = res + one } } diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt index cc3d38f9c..4ff4d7354 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt @@ -64,7 +64,8 @@ public fun Algebra.evaluate(node: MST): T = when (node) { node.left is MST.Numeric && node.right is MST.Numeric -> { val number = RealField - .binaryOperation(node.operation)(node.left.value.toDouble(), node.right.value.toDouble()) + .binaryOperation(node.operation) + .invoke(node.left.value.toDouble(), node.right.value.toDouble()) number(number) } diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt index 44a7f20b9..96703ffb8 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt @@ -24,13 +24,17 @@ public object MstSpace : Space, NumericAlgebra { public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value) public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value) - override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) - override fun multiply(a: MST, k: Number): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k)) + public override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) + public override fun MST.unaryMinus(): MST = unaryOperation(SpaceOperations.MINUS_OPERATION)(this) - override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = + public override fun multiply(a: MST, k: Number): MST.Binary = + binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k)) + + public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstAlgebra.binaryOperation(operation) - override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = MstAlgebra.unaryOperation(operation) + public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = + MstAlgebra.unaryOperation(operation) } /** @@ -47,6 +51,7 @@ public object MstRing : Ring, NumericAlgebra { public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b) public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, b) + public override fun MST.unaryMinus(): MST = MstSpace.unaryOperation(SpaceOperations.MINUS_OPERATION)(this) public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstSpace.binaryOperation(operation) @@ -71,6 +76,7 @@ public object MstField : Field { public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) public override fun divide(a: MST, b: MST): MST.Binary = binaryOperation(FieldOperations.DIV_OPERATION)(a, b) + public override fun MST.unaryMinus(): MST = MstSpace.unaryOperation(SpaceOperations.MINUS_OPERATION)(this) public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperation(operation) @@ -105,6 +111,7 @@ public object MstExtendedField : ExtendedField { public override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) + public override fun MST.unaryMinus(): MST = MstSpace.unaryOperation(SpaceOperations.MINUS_OPERATION)(this) public override fun power(arg: MST, pow: Number): MST.Binary = binaryOperation(PowerOperations.POW_OPERATION)(arg, number(pow)) diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt index 8a99fd2f4..4d1b65621 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt @@ -15,7 +15,12 @@ import kotlin.contracts.contract */ public class MstExpression>(public val algebra: A, public val mst: MST) : Expression { private inner class InnerAlgebra(val arguments: Map) : NumericAlgebra { - override fun symbol(value: String): T = arguments[StringSymbol(value)] ?: algebra.symbol(value) + override fun symbol(value: String): T = try { + algebra.symbol(value) + } catch (ignored: IllegalStateException) { + null + } ?: arguments.getValue(StringSymbol(value)) + override fun unaryOperation(operation: String): (arg: T) -> T = algebra.unaryOperation(operation) override fun binaryOperation(operation: String): (left: T, right: T) -> T = algebra.binaryOperation(operation) 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 9ccfa464c..932813182 100644 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt +++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt @@ -1,13 +1,13 @@ package kscience.kmath.asm import kscience.kmath.asm.internal.AsmBuilder -import kscience.kmath.asm.internal.MstType -import kscience.kmath.asm.internal.buildAlgebraOperationCall import kscience.kmath.asm.internal.buildName import kscience.kmath.ast.MST import kscience.kmath.ast.MstExpression import kscience.kmath.expressions.Expression import kscience.kmath.operations.Algebra +import kscience.kmath.operations.NumericAlgebra +import kscience.kmath.operations.RealField /** * Compiles given MST to an Expression using AST compiler. @@ -23,37 +23,46 @@ internal fun MST.compileWith(type: Class, algebra: Algebra): Exp is MST.Symbolic -> { val symbol = try { algebra.symbol(node.value) - } catch (ignored: Throwable) { + } catch (ignored: IllegalStateException) { null } if (symbol != null) - loadTConstant(symbol) + loadObjectConstant(symbol as Any) else loadVariable(node.value) } - is MST.Numeric -> loadNumeric(node.value) + is MST.Numeric -> loadNumberConstant(node.value) + is MST.Unary -> buildCall(algebra.unaryOperation(node.operation)) { visit(node.value) } - is MST.Unary -> buildAlgebraOperationCall( - context = algebra, - name = node.operation, - fallbackMethodName = "unaryOperation", - parameterTypes = arrayOf(MstType.fromMst(node.value)) - ) { visit(node.value) } + is MST.Binary -> when { + algebra is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> loadObjectConstant( + algebra.number( + RealField + .binaryOperation(node.operation) + .invoke(node.left.value.toDouble(), node.right.value.toDouble()) + ) + ) - is MST.Binary -> buildAlgebraOperationCall( - context = algebra, - name = node.operation, - fallbackMethodName = "binaryOperation", - parameterTypes = arrayOf(MstType.fromMst(node.left), MstType.fromMst(node.right)) - ) { - visit(node.left) - visit(node.right) + algebra is NumericAlgebra && node.left is MST.Numeric -> buildCall(algebra.leftSideNumberOperation(node.operation)) { + visit(node.left) + visit(node.right) + } + + algebra is NumericAlgebra && node.right is MST.Numeric -> buildCall(algebra.rightSideNumberOperation(node.operation)) { + visit(node.left) + visit(node.right) + } + + else -> buildCall(algebra.binaryOperation(node.operation)) { + visit(node.left) + visit(node.right) + } } } - return AsmBuilder(type, algebra, buildName(this)) { visit(this@compileWith) }.getInstance() + return AsmBuilder(type, buildName(this)) { visit(this@compileWith) }.instance } /** 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 a1e482103..792034232 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 @@ -4,26 +4,24 @@ import kscience.kmath.asm.internal.AsmBuilder.ClassLoader import kscience.kmath.ast.MST import kscience.kmath.expressions.Expression import kscience.kmath.operations.Algebra -import kscience.kmath.operations.NumericAlgebra import org.objectweb.asm.* import org.objectweb.asm.Opcodes.* import org.objectweb.asm.commons.InstructionAdapter -import java.util.* -import java.util.stream.Collectors +import java.util.stream.Collectors.toMap +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract /** * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. * This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class. * * @property T the type of AsmExpression to unwrap. - * @property algebra the algebra the applied AsmExpressions use. * @property className the unique class name of new loaded class. * @property invokeLabel0Visitor the function to apply to this object when generating invoke method, label 0. * @author Iaroslav Postovalov */ internal class AsmBuilder internal constructor( - private val classOfT: Class<*>, - private val algebra: Algebra, + classOfT: Class<*>, private val className: String, private val invokeLabel0Visitor: AsmBuilder.() -> Unit, ) { @@ -39,15 +37,10 @@ internal class AsmBuilder internal constructor( */ private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader) - /** - * ASM Type for [algebra]. - */ - private val tAlgebraType: Type = algebra.javaClass.asm - /** * ASM type for [T]. */ - internal val tType: Type = classOfT.asm + private val tType: Type = classOfT.asm /** * ASM type for new class. @@ -69,51 +62,13 @@ internal class AsmBuilder internal constructor( */ private var hasConstants: Boolean = true - /** - * States whether [T] a primitive type, so [AsmBuilder] may generate direct primitive calls. - */ - internal var primitiveMode: Boolean = false - - /** - * 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 apply for specific primitive calls. Use [OBJECT_TYPE], if not in [primitiveMode]. - */ - internal var primitiveMaskBoxed: Type = OBJECT_TYPE - - /** - * Stack of useful objects types on stack to verify types. - */ - private val typeStack: ArrayDeque = ArrayDeque() - - /** - * Stack of useful objects types on stack expected by algebra calls. - */ - internal val expectationStack: ArrayDeque = ArrayDeque(1).also { it.push(tType) } - - /** - * The cache for instance built by this builder. - */ - private var generatedInstance: Expression? = null - /** * Subclasses, loads and instantiates [Expression] for given parameters. * * The built instance is cached. */ @Suppress("UNCHECKED_CAST") - internal fun getInstance(): Expression { - generatedInstance?.let { return it } - - if (SIGNATURE_LETTERS.containsKey(classOfT)) { - primitiveMode = true - primitiveMask = SIGNATURE_LETTERS.getValue(classOfT) - primitiveMaskBoxed = tType - } - + val instance: Expression by lazy { val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { visit( V1_8, @@ -192,15 +147,6 @@ internal class AsmBuilder internal constructor( hasConstants = constants.isNotEmpty() - visitField( - access = ACC_PRIVATE or ACC_FINAL, - name = "algebra", - descriptor = tAlgebraType.descriptor, - signature = null, - value = null, - block = FieldVisitor::visitEnd - ) - if (hasConstants) visitField( access = ACC_PRIVATE or ACC_FINAL, @@ -214,25 +160,17 @@ internal class AsmBuilder internal constructor( visitMethod( ACC_PUBLIC, "", - - Type.getMethodDescriptor( - Type.VOID_TYPE, - tAlgebraType, - *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), - + Type.getMethodDescriptor(Type.VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), null, null ).instructionAdapter { val thisVar = 0 - val algebraVar = 1 - val constantsVar = 2 + val constantsVar = 1 val l0 = label() load(thisVar, classType) invokespecial(OBJECT_TYPE.internalName, "", Type.getMethodDescriptor(Type.VOID_TYPE), false) label() load(thisVar, classType) - load(algebraVar, tAlgebraType) - putfield(classType.internalName, "algebra", tAlgebraType.descriptor) if (hasConstants) { label() @@ -246,15 +184,6 @@ internal class AsmBuilder internal constructor( val l4 = label() visitLocalVariable("this", classType.descriptor, null, l0, l4, thisVar) - visitLocalVariable( - "algebra", - tAlgebraType.descriptor, - null, - l0, - l4, - algebraVar - ) - if (hasConstants) visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, constantsVar) @@ -265,33 +194,55 @@ internal class AsmBuilder internal constructor( visitEnd() } - val new = classLoader +// java.io.File("dump.class").writeBytes(classWriter.toByteArray()) + + classLoader .defineClass(className, classWriter.toByteArray()) .constructors .first() - .newInstance(algebra, *(constants.toTypedArray().wrapToArrayIf { hasConstants })) as Expression - - generatedInstance = new - return new + .newInstance(*(constants.toTypedArray().wrapToArrayIf { hasConstants })) as Expression } /** - * Loads a [T] constant from [constants]. + * Loads [java.lang.Object] constant from constants. */ - internal fun loadTConstant(value: T) { - if (classOfT in INLINABLE_NUMBERS) { - val expectedType = expectationStack.pop() - val mustBeBoxed = expectedType.sort == Type.OBJECT - loadNumberConstant(value as Number, mustBeBoxed) + fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { + val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex + loadThis() + getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) + iconst(idx) + visitInsn(AALOAD) + checkcast(type) + } - if (mustBeBoxed) - invokeMethodVisitor.checkcast(tType) + /** + * Loads `this` variable. + */ + private fun loadThis(): Unit = invokeMethodVisitor.load(invokeThisVar, classType) - if (mustBeBoxed) typeStack.push(tType) else typeStack.push(primitiveMask) + /** + * Either loads a numeric constant [value] from the class's constants field or boxes a primitive + * constant from the constant pool. + */ + fun loadNumberConstant(value: Number) { + val boxed = value.javaClass.asm + val primitive = BOXED_TO_PRIMITIVES[boxed] + + if (primitive != null) { + when (primitive) { + Type.BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + Type.DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) + Type.FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) + Type.LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) + Type.INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + Type.SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + } + + box(primitive) return } - loadObjectConstant(value as Any, tType) + loadObjectConstant(value, boxed) } /** @@ -309,77 +260,9 @@ internal class AsmBuilder internal constructor( } /** - * Unboxes the current boxed value and pushes it. + * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. */ - private fun unboxTo(primitive: Type) = invokeMethodVisitor.invokevirtual( - NUMBER_TYPE.internalName, - NUMBER_CONVERTER_METHODS.getValue(primitive), - Type.getMethodDescriptor(primitive), - false - ) - - /** - * Loads [java.lang.Object] constant from constants. - */ - private fun loadObjectConstant(value: Any, type: Type): Unit = invokeMethodVisitor.run { - val idx = if (value in constants) constants.indexOf(value) else constants.apply { add(value) }.lastIndex - loadThis() - getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) - iconst(idx) - visitInsn(AALOAD) - checkcast(type) - } - - internal fun loadNumeric(value: Number) { - if (expectationStack.peek() == NUMBER_TYPE) { - loadNumberConstant(value, true) - expectationStack.pop() - typeStack.push(NUMBER_TYPE) - } else (algebra as? NumericAlgebra)?.number(value)?.let { loadTConstant(it) } - ?: error("Cannot resolve numeric $value since target algebra is not numeric, and the current operation doesn't accept numbers.") - } - - /** - * Loads this variable. - */ - private fun loadThis(): Unit = invokeMethodVisitor.load(invokeThisVar, classType) - - /** - * Either loads a numeric constant [value] from the class's constants field or boxes a primitive - * constant from the constant pool (some numbers with special opcodes like [Opcodes.ICONST_0] aren't even loaded - * from it). - */ - private fun loadNumberConstant(value: Number, mustBeBoxed: Boolean) { - val boxed = value.javaClass.asm - val primitive = BOXED_TO_PRIMITIVES[boxed] - - if (primitive != null) { - when (primitive) { - Type.BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - Type.DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) - Type.FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) - Type.LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) - Type.INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - Type.SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - } - - if (mustBeBoxed) - box(primitive) - - return - } - - loadObjectConstant(value, boxed) - - if (!mustBeBoxed) - unboxTo(primitiveMask) - } - - /** - * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The [defaultValue] may be - * provided. - */ - internal fun loadVariable(name: String): Unit = invokeMethodVisitor.run { + fun loadVariable(name: String): Unit = invokeMethodVisitor.run { load(invokeArgumentsVar, MAP_TYPE) aconst(name) @@ -391,70 +274,28 @@ internal class AsmBuilder internal constructor( ) checkcast(tType) - val expectedType = expectationStack.pop() - - if (expectedType.sort == Type.OBJECT) - typeStack.push(tType) - else { - unboxTo(primitiveMask) - typeStack.push(primitiveMask) - } } - /** - * Loads algebra from according field of the class and casts it to class of [algebra] provided. - */ - internal fun loadAlgebra() { - loadThis() - invokeMethodVisitor.getfield(classType.internalName, "algebra", tAlgebraType.descriptor) - } + inline fun buildCall(function: Function, parameters: AsmBuilder.() -> Unit) { + contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } + val `interface` = function.javaClass.interfaces.first { it.interfaces.contains(Function::class.java) } - /** - * Writes a method instruction of opcode with its [owner], [method] and its [descriptor]. The default opcode is - * [Opcodes.INVOKEINTERFACE], since most Algebra functions are declared in interfaces. [loadAlgebra] should be - * called before the arguments and this operation. - * - * The result is casted to [T] automatically. - */ - internal fun invokeAlgebraOperation( - owner: String, - method: String, - descriptor: String, - expectedArity: Int, - opcode: Int = INVOKEINTERFACE, - ) { - run loop@{ - repeat(expectedArity) { - if (typeStack.isEmpty()) return@loop - typeStack.pop() - } - } + val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount + ?: error("Provided function object doesn't contain invoke method") - invokeMethodVisitor.visitMethodInsn( - opcode, - owner, - method, - descriptor, - opcode == INVOKEINTERFACE + val type = Type.getType(`interface`) + loadObjectConstant(function, type) + parameters(this) + + invokeMethodVisitor.invokeinterface( + type.internalName, + "invoke", + Type.getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE}), ) invokeMethodVisitor.checkcast(tType) - val isLastExpr = expectationStack.size == 1 - val expectedType = expectationStack.pop() - - if (expectedType.sort == Type.OBJECT || isLastExpr) - typeStack.push(tType) - else { - unboxTo(primitiveMask) - typeStack.push(primitiveMask) - } } - /** - * Writes a LDC Instruction with string constant provided. - */ - internal fun loadStringConstant(string: String): Unit = invokeMethodVisitor.aconst(string) - internal companion object { /** * Index of `this` variable in invoke method of the built subclass. @@ -490,32 +331,13 @@ internal class AsmBuilder internal constructor( */ private val PRIMITIVES_TO_BOXED: Map by lazy { BOXED_TO_PRIMITIVES.entries.stream().collect( - Collectors.toMap( + toMap( Map.Entry::value, Map.Entry::key ) ) } - /** - * Maps primitive ASM types to [Number] functions unboxing them. - */ - private val NUMBER_CONVERTER_METHODS: Map by lazy { - hashMapOf( - Type.BYTE_TYPE to "byteValue", - Type.SHORT_TYPE to "shortValue", - Type.INT_TYPE to "intValue", - Type.LONG_TYPE to "longValue", - Type.FLOAT_TYPE to "floatValue", - Type.DOUBLE_TYPE to "doubleValue" - ) - } - - /** - * 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 } - /** * ASM type for [Expression]. */ diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/MstType.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/MstType.kt deleted file mode 100644 index 526c27305..000000000 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/MstType.kt +++ /dev/null @@ -1,20 +0,0 @@ -package kscience.kmath.asm.internal - -import kscience.kmath.ast.MST - -/** - * Represents types known in [MST], numbers and general values. - */ -internal enum class MstType { - GENERAL, - NUMBER; - - companion object { - fun fromMst(mst: MST): MstType { - if (mst is MST.Numeric) - return NUMBER - - return GENERAL - } - } -} 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 ef9751502..d301ddf15 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 @@ -2,29 +2,11 @@ package kscience.kmath.asm.internal import kscience.kmath.ast.MST import kscience.kmath.expressions.Expression -import kscience.kmath.operations.Algebra -import kscience.kmath.operations.FieldOperations -import kscience.kmath.operations.RingOperations -import kscience.kmath.operations.SpaceOperations 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 -private val methodNameAdapters: Map, String> by lazy { - hashMapOf( - SpaceOperations.PLUS_OPERATION to 2 to "add", - RingOperations.TIMES_OPERATION to 2 to "multiply", - FieldOperations.DIV_OPERATION to 2 to "divide", - SpaceOperations.PLUS_OPERATION to 1 to "unaryPlus", - SpaceOperations.MINUS_OPERATION to 1 to "unaryMinus", - SpaceOperations.MINUS_OPERATION to 2 to "minus" - ) -} - /** * Returns ASM [Type] for given [Class]. * @@ -110,106 +92,4 @@ internal inline fun ClassWriter.visitField( return visitField(access, name, descriptor, signature, value).apply(block) } -private fun AsmBuilder.findSpecific(context: Algebra, name: String, parameterTypes: Array): Method? = - context.javaClass.methods.find { method -> - val nameValid = method.name == name - val arityValid = method.parameters.size == parameterTypes.size - val notBridgeInPrimitive = !(primitiveMode && method.isBridge) - val paramsValid = method.parameterTypes.zip(parameterTypes).all { (type, mstType) -> - !(mstType != MstType.NUMBER && type == java.lang.Number::class.java) - } - - nameValid && arityValid && notBridgeInPrimitive && paramsValid - } - -/** - * Checks if the target [context] for code generation contains a method with needed [name] and arity, also builds - * type expectation stack for needed arity. - * - * @author Iaroslav Postovalov - */ -private fun AsmBuilder.buildExpectationStack( - context: Algebra, - name: String, - parameterTypes: Array -): Boolean { - val arity = parameterTypes.size - val specific = findSpecific(context, methodNameAdapters[name to arity] ?: name, parameterTypes) - - if (specific != null) - mapTypes(specific, parameterTypes).reversed().forEach { expectationStack.push(it) } - else - expectationStack.addAll(Collections.nCopies(arity, tType)) - - return specific != null -} - -private fun AsmBuilder.mapTypes(method: Method, parameterTypes: Array): List = method - .parameterTypes - .zip(parameterTypes) - .map { (type, mstType) -> - when { - type == java.lang.Number::class.java && mstType == MstType.NUMBER -> AsmBuilder.NUMBER_TYPE - else -> if (primitiveMode) primitiveMask else primitiveMaskBoxed - } - } - -/** - * Checks if the target [context] for code generation contains a method with needed [name] and arity and inserts - * [AsmBuilder.invokeAlgebraOperation] of this method. - * - * @author Iaroslav Postovalov - */ -private fun AsmBuilder.tryInvokeSpecific( - context: Algebra, - name: String, - parameterTypes: Array -): Boolean { - val arity = parameterTypes.size - val theName = methodNameAdapters[name to arity] ?: name - val spec = findSpecific(context, theName, parameterTypes) ?: return false - val owner = context.javaClass.asm - - invokeAlgebraOperation( - owner = owner.internalName, - method = theName, - descriptor = Type.getMethodDescriptor(primitiveMaskBoxed, *mapTypes(spec, parameterTypes).toTypedArray()), - expectedArity = arity, - opcode = INVOKEVIRTUAL - ) - - return true -} - -/** - * Builds specialized [context] call with option to fallback to generic algebra operation accepting [String]. - * - * @author Iaroslav Postovalov - */ -internal inline fun AsmBuilder.buildAlgebraOperationCall( - context: Algebra, - name: String, - fallbackMethodName: String, - parameterTypes: Array, - parameters: AsmBuilder.() -> Unit -) { - contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } - val arity = parameterTypes.size - loadAlgebra() - if (!buildExpectationStack(context, name, parameterTypes)) loadStringConstant(name) - parameters() - - if (!tryInvokeSpecific(context, name, parameterTypes)) invokeAlgebraOperation( - owner = AsmBuilder.ALGEBRA_TYPE.internalName, - method = fallbackMethodName, - - descriptor = Type.getMethodDescriptor( - AsmBuilder.OBJECT_TYPE, - AsmBuilder.STRING_TYPE, - *Array(arity) { AsmBuilder.OBJECT_TYPE } - ), - - expectedArity = arity - ) -} diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt index 5eebfe43d..a1687c1c7 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt @@ -10,15 +10,11 @@ import kotlin.test.Test import kotlin.test.assertEquals internal class TestAsmAlgebras { - @Test fun space() { val res1 = ByteRing.mstInSpace { - binaryOperation( - "+", - - unaryOperation( - "+", + binaryOperation("+")( + unaryOperation("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( add(number(1), number(1)), 2 @@ -30,11 +26,8 @@ internal class TestAsmAlgebras { }("x" to 2.toByte()) val res2 = ByteRing.mstInSpace { - binaryOperation( - "+", - - unaryOperation( - "+", + binaryOperation("+")( + unaryOperation("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( add(number(1), number(1)), 2 @@ -51,11 +44,8 @@ internal class TestAsmAlgebras { @Test fun ring() { val res1 = ByteRing.mstInRing { - binaryOperation( - "+", - - unaryOperation( - "+", + binaryOperation("+")( + unaryOperation("+")( (symbol("x") - (2.toByte() + (multiply( add(number(1), number(1)), 2 @@ -67,17 +57,13 @@ internal class TestAsmAlgebras { }("x" to 3.toByte()) val res2 = ByteRing.mstInRing { - binaryOperation( - "+", - - unaryOperation( - "+", + binaryOperation("+")( + unaryOperation("+")( (symbol("x") - (2.toByte() + (multiply( add(number(1), number(1)), 2 ) + 1.toByte()))) * 3.0 - 1.toByte() ), - number(1) ) * number(2) }.compile()("x" to 3.toByte()) @@ -88,8 +74,7 @@ internal class TestAsmAlgebras { @Test fun field() { val res1 = RealField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation( - "+", + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one @@ -97,8 +82,7 @@ internal class TestAsmAlgebras { }("x" to 2.0) val res2 = RealField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation( - "+", + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt index 7f4d453f7..acd9e21ea 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt @@ -1,10 +1,11 @@ package kscience.kmath.asm -import kscience.kmath.asm.compile +import kscience.kmath.ast.mstInExtendedField import kscience.kmath.ast.mstInField import kscience.kmath.ast.mstInSpace import kscience.kmath.expressions.invoke import kscience.kmath.operations.RealField +import kotlin.random.Random import kotlin.test.Test import kotlin.test.assertEquals @@ -28,4 +29,13 @@ internal class TestAsmExpressions { val res = RealField.mstInField { symbol("x") * 2 }("x" to 2.0) assertEquals(4.0, res) } + + @Test + fun testMultipleCalls() { + val e = RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile() + val r = Random(0) + var s = 0.0 + repeat(1000000) { s += e("x" to r.nextDouble()) } + println(s) + } } diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt index eb5a1c8f3..ce9e602d3 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt @@ -46,7 +46,7 @@ internal class TestAsmSpecialization { @Test fun testPower() { val expr = RealField - .mstInField { binaryOperation("power")(symbol("x"), number(2)) } + .mstInField { binaryOperation("pow")(symbol("x"), number(2)) } .compile() assertEquals(4.0, expr("x" to 2.0)) diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt index 7b89c74fa..1011515c8 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt @@ -17,6 +17,6 @@ internal class TestAsmVariables { @Test fun testVariableWithoutDefaultFails() { val expr = ByteRing.mstInRing { symbol("x") } - assertFailsWith { expr() } + assertFailsWith { expr() } } } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index 19ca1a4cc..2661525fb 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -20,12 +20,14 @@ public interface Algebra { /** * Dynamically dispatches an unary operation with name [operation]. */ - public fun unaryOperation(operation: String): (arg: T) -> T + public fun unaryOperation(operation: String): (arg: T) -> T = + error("Unary operation $operation not defined in $this") /** * Dynamically dispatches a binary operation with name [operation]. */ - public fun binaryOperation(operation: String): (left: T, right: T) -> T + public fun binaryOperation(operation: String): (left: T, right: T) -> T = + error("Binary operation $operation not defined in $this") } /** @@ -161,13 +163,13 @@ public interface SpaceOperations : Algebra { override fun unaryOperation(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> arg } MINUS_OPERATION -> { arg -> -arg } - else -> error("Unary operation $operation not defined in $this") + else -> super.unaryOperation(operation) } override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { PLUS_OPERATION -> ::add MINUS_OPERATION -> { left, right -> left - right } - else -> error("Binary operation $operation not defined in $this") + else -> super.binaryOperation(operation) } public companion object { diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt index 611222d34..cd2bd0417 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt @@ -31,7 +31,7 @@ public interface ExtendedFieldOperations : PowerOperations.SQRT_OPERATION -> ::sqrt ExponentialOperations.EXP_OPERATION -> ::exp ExponentialOperations.LN_OPERATION -> ::ln - else -> super.unaryOperation(operation) + else -> super.unaryOperation(operation) } } From cc45e3683b702b8c8e637af66d7cf07d67dcbd24 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 8 Dec 2020 16:16:32 +0700 Subject: [PATCH 04/55] Refactor ASM builder --- .../kscience/kmath/asm/internal/AsmBuilder.kt | 129 +++++++----------- .../kmath/asm/internal/codegenUtils.kt | 2 - 2 files changed, 53 insertions(+), 78 deletions(-) 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 792034232..46051e158 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 @@ -6,6 +6,7 @@ import kscience.kmath.expressions.Expression import kscience.kmath.operations.Algebra import org.objectweb.asm.* import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.Type.* import org.objectweb.asm.commons.InstructionAdapter import java.util.stream.Collectors.toMap import kotlin.contracts.InvocationKind @@ -17,13 +18,13 @@ import kotlin.contracts.contract * * @property T the type of AsmExpression to unwrap. * @property className the unique class name of new loaded class. - * @property invokeLabel0Visitor the function to apply to this object when generating invoke method, label 0. + * @property callbackAtInvokeL0 the function to apply to this object when generating invoke method, label 0. * @author Iaroslav Postovalov */ -internal class AsmBuilder internal constructor( +internal class AsmBuilder( classOfT: Class<*>, private val className: String, - private val invokeLabel0Visitor: AsmBuilder.() -> Unit, + private val callbackAtInvokeL0: AsmBuilder.() -> Unit, ) { /** * Internal classloader of [AsmBuilder] with alias to define class from byte array. @@ -45,7 +46,7 @@ internal class AsmBuilder internal constructor( /** * ASM type for new class. */ - private val classType: Type = Type.getObjectType(className.replace(oldChar = '.', newChar = '/'))!! + private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) /** * List of constants to provide to the subclass. @@ -57,11 +58,6 @@ internal class AsmBuilder internal constructor( */ private lateinit var invokeMethodVisitor: InstructionAdapter - /** - * States whether this [AsmBuilder] needs to generate constants field. - */ - private var hasConstants: Boolean = true - /** * Subclasses, loads and instantiates [Expression] for given parameters. * @@ -69,6 +65,8 @@ internal class AsmBuilder internal constructor( */ @Suppress("UNCHECKED_CAST") val instance: Expression by lazy { + val hasConstants: Boolean + val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { visit( V1_8, @@ -82,14 +80,14 @@ internal class AsmBuilder internal constructor( visitMethod( ACC_PUBLIC or ACC_FINAL, "invoke", - Type.getMethodDescriptor(tType, MAP_TYPE), + getMethodDescriptor(tType, MAP_TYPE), "(L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", null ).instructionAdapter { invokeMethodVisitor = this visitCode() val l0 = label() - invokeLabel0Visitor() + callbackAtInvokeL0() areturn(tType) val l1 = label() @@ -99,7 +97,7 @@ internal class AsmBuilder internal constructor( null, l0, l1, - invokeThisVar + 0 ) visitLocalVariable( @@ -108,7 +106,7 @@ internal class AsmBuilder internal constructor( "L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;", l0, l1, - invokeArgumentsVar + 1 ) visitMaxs(0, 2) @@ -118,7 +116,7 @@ internal class AsmBuilder internal constructor( visitMethod( ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, "invoke", - Type.getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), null, null ).instructionAdapter { @@ -128,7 +126,7 @@ internal class AsmBuilder internal constructor( val l0 = label() load(thisVar, OBJECT_TYPE) load(argumentsVar, MAP_TYPE) - invokevirtual(classType.internalName, "invoke", Type.getMethodDescriptor(tType, MAP_TYPE), false) + invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) areturn(tType) val l1 = label() @@ -160,32 +158,30 @@ internal class AsmBuilder internal constructor( visitMethod( ACC_PUBLIC, "", - Type.getMethodDescriptor(Type.VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), + getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), null, null ).instructionAdapter { - val thisVar = 0 - val constantsVar = 1 val l0 = label() - load(thisVar, classType) - invokespecial(OBJECT_TYPE.internalName, "", Type.getMethodDescriptor(Type.VOID_TYPE), false) + load(0, classType) + invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) label() - load(thisVar, classType) + load(0, classType) if (hasConstants) { label() - load(thisVar, classType) - load(constantsVar, OBJECT_ARRAY_TYPE) + load(0, classType) + load(1, OBJECT_ARRAY_TYPE) putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) } label() visitInsn(RETURN) val l4 = label() - visitLocalVariable("this", classType.descriptor, null, l0, l4, thisVar) + visitLocalVariable("this", classType.descriptor, null, l0, l4, 0) if (hasConstants) - visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, constantsVar) + visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, 1) visitMaxs(0, 3) visitEnd() @@ -218,7 +214,7 @@ internal class AsmBuilder internal constructor( /** * Loads `this` variable. */ - private fun loadThis(): Unit = invokeMethodVisitor.load(invokeThisVar, classType) + private fun loadThis(): Unit = invokeMethodVisitor.load(0, classType) /** * Either loads a numeric constant [value] from the class's constants field or boxes a primitive @@ -230,12 +226,12 @@ internal class AsmBuilder internal constructor( if (primitive != null) { when (primitive) { - Type.BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - Type.DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) - Type.FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) - Type.LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) - Type.INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - Type.SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) + FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) + LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) + INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) } box(primitive) @@ -254,7 +250,7 @@ internal class AsmBuilder internal constructor( invokeMethodVisitor.invokestatic( r.internalName, "valueOf", - Type.getMethodDescriptor(r, primitive), + getMethodDescriptor(r, primitive), false ) } @@ -263,13 +259,13 @@ internal class AsmBuilder internal constructor( * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. */ fun loadVariable(name: String): Unit = invokeMethodVisitor.run { - load(invokeArgumentsVar, MAP_TYPE) + load(1, MAP_TYPE) aconst(name) invokestatic( MAP_INTRINSICS_TYPE.internalName, "getOrFail", - Type.getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), false ) @@ -283,100 +279,81 @@ internal class AsmBuilder internal constructor( val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount ?: error("Provided function object doesn't contain invoke method") - val type = Type.getType(`interface`) + val type = getType(`interface`) loadObjectConstant(function, type) parameters(this) invokeMethodVisitor.invokeinterface( type.internalName, "invoke", - Type.getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE}), + getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE }), ) invokeMethodVisitor.checkcast(tType) } - 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 { - hashMapOf( - 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 - ) - } - + companion object { /** * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. */ - private val BOXED_TO_PRIMITIVES: Map by lazy { SIGNATURE_LETTERS.mapKeys { (k, _) -> k.asm } } + private val BOXED_TO_PRIMITIVES: Map by lazy { + hashMapOf( + Byte::class.java.asm to BYTE_TYPE, + Short::class.java.asm to SHORT_TYPE, + Integer::class.java.asm to INT_TYPE, + Long::class.java.asm to LONG_TYPE, + Float::class.java.asm to FLOAT_TYPE, + Double::class.java.asm to DOUBLE_TYPE, + ) + } /** * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. */ private val PRIMITIVES_TO_BOXED: Map by lazy { BOXED_TO_PRIMITIVES.entries.stream().collect( - toMap( - Map.Entry::value, - Map.Entry::key - ) + toMap(Map.Entry::value, Map.Entry::key), ) } /** * ASM type for [Expression]. */ - internal val EXPRESSION_TYPE: Type by lazy { Type.getObjectType("kscience/kmath/expressions/Expression") } + val EXPRESSION_TYPE: Type by lazy { getObjectType("kscience/kmath/expressions/Expression") } /** * ASM type for [java.lang.Number]. */ - internal val NUMBER_TYPE: Type by lazy { Type.getObjectType("java/lang/Number") } + val NUMBER_TYPE: Type by lazy { getObjectType("java/lang/Number") } /** * ASM type for [java.util.Map]. */ - internal val MAP_TYPE: Type by lazy { Type.getObjectType("java/util/Map") } + val MAP_TYPE: Type by lazy { getObjectType("java/util/Map") } /** * ASM type for [java.lang.Object]. */ - internal val OBJECT_TYPE: Type by lazy { Type.getObjectType("java/lang/Object") } + val OBJECT_TYPE: Type by lazy { 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 { Type.getType("[Ljava/lang/Object;") } + val OBJECT_ARRAY_TYPE: Type by lazy { getType("[Ljava/lang/Object;") } /** * ASM type for [Algebra]. */ - internal val ALGEBRA_TYPE: Type by lazy { Type.getObjectType("kscience/kmath/operations/Algebra") } + val ALGEBRA_TYPE: Type by lazy { getObjectType("kscience/kmath/operations/Algebra") } /** * ASM type for [java.lang.String]. */ - internal val STRING_TYPE: Type by lazy { Type.getObjectType("java/lang/String") } + val STRING_TYPE: Type by lazy { getObjectType("java/lang/String") } /** * ASM type for MapIntrinsics. */ - internal val MAP_INTRINSICS_TYPE: Type by lazy { Type.getObjectType("kscience/kmath/asm/internal/MapIntrinsics") } + val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("kscience/kmath/asm/internal/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 d301ddf15..6d5d19d42 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 @@ -91,5 +91,3 @@ internal inline fun ClassWriter.visitField( contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return visitField(access, name, descriptor, signature, value).apply(block) } - - From 95c1504c00006eb4f5096b569cede64788032f93 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 9 Dec 2020 11:41:37 +0700 Subject: [PATCH 05/55] Add cast microoptimization to AsmBuilder --- .../kscience/kmath/asm/internal/AsmBuilder.kt | 35 ++++++------------- 1 file changed, 11 insertions(+), 24 deletions(-) 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 46051e158..eb0f60f4d 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 @@ -3,7 +3,6 @@ package kscience.kmath.asm.internal import kscience.kmath.asm.internal.AsmBuilder.ClassLoader import kscience.kmath.ast.MST import kscience.kmath.expressions.Expression -import kscience.kmath.operations.Algebra import org.objectweb.asm.* import org.objectweb.asm.Opcodes.* import org.objectweb.asm.Type.* @@ -74,7 +73,7 @@ internal class AsmBuilder( classType.internalName, "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", OBJECT_TYPE.internalName, - arrayOf(EXPRESSION_TYPE.internalName) + arrayOf(EXPRESSION_TYPE.internalName), ) visitMethod( @@ -82,7 +81,7 @@ internal class AsmBuilder( "invoke", getMethodDescriptor(tType, MAP_TYPE), "(L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", - null + null, ).instructionAdapter { invokeMethodVisitor = this visitCode() @@ -97,7 +96,7 @@ internal class AsmBuilder( null, l0, l1, - 0 + 0, ) visitLocalVariable( @@ -106,7 +105,7 @@ internal class AsmBuilder( "L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;", l0, l1, - 1 + 1, ) visitMaxs(0, 2) @@ -118,14 +117,12 @@ internal class AsmBuilder( "invoke", getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), null, - null + null, ).instructionAdapter { - val thisVar = 0 - val argumentsVar = 1 visitCode() val l0 = label() - load(thisVar, OBJECT_TYPE) - load(argumentsVar, MAP_TYPE) + load(0, OBJECT_TYPE) + load(1, MAP_TYPE) invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) areturn(tType) val l1 = label() @@ -136,7 +133,7 @@ internal class AsmBuilder( null, l0, l1, - thisVar + 0, ) visitMaxs(0, 2) @@ -152,7 +149,7 @@ internal class AsmBuilder( descriptor = OBJECT_ARRAY_TYPE.descriptor, signature = null, value = null, - block = FieldVisitor::visitEnd + block = FieldVisitor::visitEnd, ) visitMethod( @@ -208,7 +205,7 @@ internal class AsmBuilder( getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) iconst(idx) visitInsn(AALOAD) - checkcast(type) + if (type != OBJECT_TYPE) checkcast(type) } /** @@ -266,7 +263,7 @@ internal class AsmBuilder( MAP_INTRINSICS_TYPE.internalName, "getOrFail", getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), - false + false, ) checkcast(tType) @@ -321,11 +318,6 @@ internal class AsmBuilder( */ val EXPRESSION_TYPE: Type by lazy { getObjectType("kscience/kmath/expressions/Expression") } - /** - * ASM type for [java.lang.Number]. - */ - val NUMBER_TYPE: Type by lazy { getObjectType("java/lang/Number") } - /** * ASM type for [java.util.Map]. */ @@ -341,11 +333,6 @@ internal class AsmBuilder( */ val OBJECT_ARRAY_TYPE: Type by lazy { getType("[Ljava/lang/Object;") } - /** - * ASM type for [Algebra]. - */ - val ALGEBRA_TYPE: Type by lazy { getObjectType("kscience/kmath/operations/Algebra") } - /** * ASM type for [java.lang.String]. */ From 07d6d891928d89d3eb14917cfbf78d790e4883b8 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 9 Dec 2020 14:43:37 +0700 Subject: [PATCH 06/55] Replace reflective constructor invocation with method handle --- .../kscience/kmath/asm/internal/AsmBuilder.kt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) 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 eb0f60f4d..d146afeee 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 @@ -7,6 +7,8 @@ import org.objectweb.asm.* import org.objectweb.asm.Opcodes.* import org.objectweb.asm.Type.* import org.objectweb.asm.commons.InstructionAdapter +import java.lang.invoke.MethodHandles +import java.lang.invoke.MethodType import java.util.stream.Collectors.toMap import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -187,13 +189,14 @@ internal class AsmBuilder( visitEnd() } -// java.io.File("dump.class").writeBytes(classWriter.toByteArray()) + val cls = classLoader.defineClass(className, classWriter.toByteArray()) + val l = MethodHandles.publicLookup() - classLoader - .defineClass(className, classWriter.toByteArray()) - .constructors - .first() - .newInstance(*(constants.toTypedArray().wrapToArrayIf { hasConstants })) as Expression + if (hasConstants) + l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java)) + .invoke(constants.toTypedArray()) as Expression + else + l.findConstructor(cls, MethodType.methodType(Void.TYPE)).invoke() as Expression } /** @@ -248,7 +251,7 @@ internal class AsmBuilder( r.internalName, "valueOf", getMethodDescriptor(r, primitive), - false + false, ) } From bdd33ca6ca608663882616f1b8147fe0f65d070c Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 00:40:18 +0700 Subject: [PATCH 07/55] Add dependencies needed for ESTree codegen --- kmath-ast/build.gradle.kts | 6 + kmath-ast/src/jsMain/kotlin/Codegen.kt | 0 kmath-ast/src/jsMain/kotlin/astring.d.ts | 50 ++ kmath-ast/src/jsMain/kotlin/astring.global.kt | 17 + kmath-ast/src/jsMain/kotlin/astring.kt | 32 + kmath-ast/src/jsMain/kotlin/emitter.d.ts | 19 + kmath-ast/src/jsMain/kotlin/emitter.kt | 18 + kmath-ast/src/jsMain/kotlin/estree.d.ts | 569 +++++++++++++++ kmath-ast/src/jsMain/kotlin/estree.kt | 647 ++++++++++++++++++ .../src/jsMain/kotlin/lib.es2015.iterable.kt | 40 ++ kmath-ast/src/jsMain/kotlin/lib.es5.kt | 86 +++ kmath-ast/src/jsMain/kotlin/stream.d.ts | 5 + kmath-ast/src/jsMain/kotlin/stream.kt | 9 + 13 files changed, 1498 insertions(+) create mode 100644 kmath-ast/src/jsMain/kotlin/Codegen.kt create mode 100644 kmath-ast/src/jsMain/kotlin/astring.d.ts create mode 100644 kmath-ast/src/jsMain/kotlin/astring.global.kt create mode 100644 kmath-ast/src/jsMain/kotlin/astring.kt create mode 100644 kmath-ast/src/jsMain/kotlin/emitter.d.ts create mode 100644 kmath-ast/src/jsMain/kotlin/emitter.kt create mode 100644 kmath-ast/src/jsMain/kotlin/estree.d.ts create mode 100644 kmath-ast/src/jsMain/kotlin/estree.kt create mode 100644 kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt create mode 100644 kmath-ast/src/jsMain/kotlin/lib.es5.kt create mode 100644 kmath-ast/src/jsMain/kotlin/stream.d.ts create mode 100644 kmath-ast/src/jsMain/kotlin/stream.kt diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 3e3c0475f..e3884025d 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -9,6 +9,12 @@ kotlin.sourceSets { } } + jsMain { + dependencies { + implementation(npm("astring", "1.4.3")) + } + } + jvmMain { dependencies { api("com.github.h0tk3y.betterParse:better-parse:0.4.0") diff --git a/kmath-ast/src/jsMain/kotlin/Codegen.kt b/kmath-ast/src/jsMain/kotlin/Codegen.kt new file mode 100644 index 000000000..e69de29bb diff --git a/kmath-ast/src/jsMain/kotlin/astring.d.ts b/kmath-ast/src/jsMain/kotlin/astring.d.ts new file mode 100644 index 000000000..22cd7e980 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/astring.d.ts @@ -0,0 +1,50 @@ +// Type definitions for astring 1.3 +// Project: https://github.com/davidbonnet/astring +// Definitions by: Nikolaj Kappler +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +import * as ESTree from 'estree'; +import 'node'; +import { Stream } from 'stream'; + +export interface Options { + /** string to use for indentation (defaults to " ") */ + indent?: string; + /** string to use for line endings (defaults to "\n") */ + lineEnd?: string; + /** indent level to start from (defaults to 0) */ + startingIndentLevel?: number; + /** generate comments if true (defaults to false) */ + comments?: boolean; + /** custom code generator (defaults to astring.baseGenerator) */ + generator?: object; + /** source map generator (defaults to null), see https://github.com/mozilla/source-map#sourcemapgenerator */ + sourceMap?: any; +} + +/** Returns a string representing the rendered code of the provided AST `node`. However, if an `output` stream is provided in the options, it writes to that stream and returns it. */ +export function generate(node: ESTree.Node, options?: Options): string; +/** Returns a string representing the rendered code of the provided AST `node`. However, if an `output` stream is provided in the options, it writes to that stream and returns it. */ +export function generate(node: ESTree.Node, options: Options & { + /** output stream to write the rendered code to (defaults to null) */ + output: Stream; +}): Stream; + +/** + * A code generator consists of a mapping of node names and functions that take two arguments: `node` and `state`. + * The `node` points to the node from which to generate the code and the `state` exposes the `write` method that takes generated code strings. + */ +export type Generator = { [key in ESTree.Node["type"]]: (node: Extract, state: { write(s: string): void }) => void }; + +/** Base generator that can be used to extend Astring. See https://github.com/davidbonnet/astring#extending */ +export const baseGenerator: Generator; + +declare global { + interface astring { + generate: typeof generate; + /** Base generator that can be used to extend Astring. See https://github.com/davidbonnet/astring#extending */ + baseGenerator: Generator; + } + const astring: astring; +} \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/astring.global.kt b/kmath-ast/src/jsMain/kotlin/astring.global.kt new file mode 100644 index 000000000..78c771f26 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/astring.global.kt @@ -0,0 +1,17 @@ +@file:JsQualifier("global") +@file:Suppress( + "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", + "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "PackageDirectoryMismatch", "ClassName" +) + +package global + +import Generator + +@Suppress("EXTERNAL_DELEGATION", "NESTED_CLASS_IN_EXTERNAL_INTERFACE") +external interface astring { + var generate: Any + var baseGenerator: Generator + + companion object : astring by definedExternally +} \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/astring.kt b/kmath-ast/src/jsMain/kotlin/astring.kt new file mode 100644 index 000000000..e9ab6f627 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/astring.kt @@ -0,0 +1,32 @@ +@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", + "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation" +) + +external interface Options { + var indent: String? + get() = definedExternally + set(value) = definedExternally + var lineEnd: String? + get() = definedExternally + set(value) = definedExternally + var startingIndentLevel: Number? + get() = definedExternally + set(value) = definedExternally + var comments: Boolean? + get() = definedExternally + set(value) = definedExternally + var generator: Any? + get() = definedExternally + set(value) = definedExternally + var sourceMap: Any? + get() = definedExternally + set(value) = definedExternally +} + +external fun generate(node: BaseNode, options: Options /* Options & `T$0` */ = definedExternally): String + +external fun generate(node: BaseNode): String + +typealias Generator = Any + +external var baseGenerator: Generator \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/emitter.d.ts b/kmath-ast/src/jsMain/kotlin/emitter.d.ts new file mode 100644 index 000000000..ea0319cd6 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/emitter.d.ts @@ -0,0 +1,19 @@ +export class Emitter { + constructor(obj: any) + constructor() + + on(event: string, fn: () => void) + + off(event: string, fn: () => void) + + once(event: string, fn: () => void) + + emit(event: string, ...any: any[]) + + listeners(event: string): (() => void)[] + + hasListeners(event: string): boolean +} + + +function mixin(obj: any): any diff --git a/kmath-ast/src/jsMain/kotlin/emitter.kt b/kmath-ast/src/jsMain/kotlin/emitter.kt new file mode 100644 index 000000000..ad0a16bf7 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/emitter.kt @@ -0,0 +1,18 @@ +@file:Suppress( + "INTERFACE_WITH_SUPERCLASS", + "OVERRIDING_FINAL_MEMBER", + "RETURN_TYPE_MISMATCH_ON_OVERRIDE", + "CONFLICTING_OVERLOADS", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "SortModifiers" +) + +external open class Emitter { + constructor(obj: Any) + constructor() + + open fun on(event: String, fn: () -> Unit) + open fun off(event: String, fn: () -> Unit) + open fun once(event: String, fn: () -> Unit) + open fun emit(event: String, vararg any: Any) + open fun listeners(event: String): Array<() -> Unit> + open fun hasListeners(event: String): Boolean +} \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/estree.d.ts b/kmath-ast/src/jsMain/kotlin/estree.d.ts new file mode 100644 index 000000000..927477c66 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/estree.d.ts @@ -0,0 +1,569 @@ +// Type definitions for ESTree AST specification +// Project: https://github.com/estree/estree +// Definitions by: RReverser +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +// This definition file follows a somewhat unusual format. ESTree allows +// runtime type checks based on the `type` parameter. In order to explain this +// to typescript we want to use discriminated union types: +// https://github.com/Microsoft/TypeScript/pull/9163 +// +// For ESTree this is a bit tricky because the high level interfaces like +// Node or Function are pulling double duty. We want to pass common fields down +// to the interfaces that extend them (like Identifier or +// ArrowFunctionExpression), but you can't extend a type union or enforce +// common fields on them. So we've split the high level interfaces into two +// types, a base type which passes down inhereted fields, and a type union of +// all types which extend the base type. Only the type union is exported, and +// the union is how other types refer to the collection of inheriting types. +// +// This makes the definitions file here somewhat more difficult to maintain, +// but it has the notable advantage of making ESTree much easier to use as +// an end user. + +interface BaseNodeWithoutComments { + // Every leaf interface that extends BaseNode must specify a type property. + // The type property should be a string literal. For example, Identifier + // has: `type: "Identifier"` + type: string; + loc?: SourceLocation | null; + range?: [number, number]; +} + +interface BaseNode extends BaseNodeWithoutComments { + leadingComments?: Array; + trailingComments?: Array; +} + +export type Node = + Identifier | Literal | Program | Function | SwitchCase | CatchClause | + VariableDeclarator | Statement | Expression | Property | + AssignmentProperty | Super | TemplateElement | SpreadElement | Pattern | + ClassBody | Class | MethodDefinition | ModuleDeclaration | ModuleSpecifier; + +export interface Comment extends BaseNodeWithoutComments { + type: "Line" | "Block"; + value: string; +} + +interface SourceLocation { + source?: string | null; + start: Position; + end: Position; +} + +export interface Position { + /** >= 1 */ + line: number; + /** >= 0 */ + column: number; +} + +export interface Program extends BaseNode { + type: "Program"; + sourceType: "script" | "module"; + body: Array; + comments?: Array; +} + +export interface Directive extends BaseNode { + type: "ExpressionStatement"; + expression: Literal; + directive: string; +} + +interface BaseFunction extends BaseNode { + params: Array; + generator?: boolean; + async?: boolean; + // The body is either BlockStatement or Expression because arrow functions + // can have a body that's either. FunctionDeclarations and + // FunctionExpressions have only BlockStatement bodies. + body: BlockStatement | Expression; +} + +export type Function = + FunctionDeclaration | FunctionExpression | ArrowFunctionExpression; + +export type Statement = + ExpressionStatement | BlockStatement | EmptyStatement | + DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | + BreakStatement | ContinueStatement | IfStatement | SwitchStatement | + ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | + ForStatement | ForInStatement | ForOfStatement | Declaration; + +interface BaseStatement extends BaseNode { } + +export interface EmptyStatement extends BaseStatement { + type: "EmptyStatement"; +} + +export interface BlockStatement extends BaseStatement { + type: "BlockStatement"; + body: Array; + innerComments?: Array; +} + +export interface ExpressionStatement extends BaseStatement { + type: "ExpressionStatement"; + expression: Expression; +} + +export interface IfStatement extends BaseStatement { + type: "IfStatement"; + test: Expression; + consequent: Statement; + alternate?: Statement | null; +} + +export interface LabeledStatement extends BaseStatement { + type: "LabeledStatement"; + label: Identifier; + body: Statement; +} + +export interface BreakStatement extends BaseStatement { + type: "BreakStatement"; + label?: Identifier | null; +} + +export interface ContinueStatement extends BaseStatement { + type: "ContinueStatement"; + label?: Identifier | null; +} + +export interface WithStatement extends BaseStatement { + type: "WithStatement"; + object: Expression; + body: Statement; +} + +export interface SwitchStatement extends BaseStatement { + type: "SwitchStatement"; + discriminant: Expression; + cases: Array; +} + +export interface ReturnStatement extends BaseStatement { + type: "ReturnStatement"; + argument?: Expression | null; +} + +export interface ThrowStatement extends BaseStatement { + type: "ThrowStatement"; + argument: Expression; +} + +export interface TryStatement extends BaseStatement { + type: "TryStatement"; + block: BlockStatement; + handler?: CatchClause | null; + finalizer?: BlockStatement | null; +} + +export interface WhileStatement extends BaseStatement { + type: "WhileStatement"; + test: Expression; + body: Statement; +} + +export interface DoWhileStatement extends BaseStatement { + type: "DoWhileStatement"; + body: Statement; + test: Expression; +} + +export interface ForStatement extends BaseStatement { + type: "ForStatement"; + init?: VariableDeclaration | Expression | null; + test?: Expression | null; + update?: Expression | null; + body: Statement; +} + +interface BaseForXStatement extends BaseStatement { + left: VariableDeclaration | Pattern; + right: Expression; + body: Statement; +} + +export interface ForInStatement extends BaseForXStatement { + type: "ForInStatement"; +} + +export interface DebuggerStatement extends BaseStatement { + type: "DebuggerStatement"; +} + +export type Declaration = + FunctionDeclaration | VariableDeclaration | ClassDeclaration; + +interface BaseDeclaration extends BaseStatement { } + +export interface FunctionDeclaration extends BaseFunction, BaseDeclaration { + type: "FunctionDeclaration"; + /** It is null when a function declaration is a part of the `export default function` statement */ + id: Identifier | null; + body: BlockStatement; +} + +export interface VariableDeclaration extends BaseDeclaration { + type: "VariableDeclaration"; + declarations: Array; + kind: "var" | "let" | "const"; +} + +export interface VariableDeclarator extends BaseNode { + type: "VariableDeclarator"; + id: Pattern; + init?: Expression | null; +} + +type Expression = + ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | + ArrowFunctionExpression | YieldExpression | Literal | UnaryExpression | + UpdateExpression | BinaryExpression | AssignmentExpression | + LogicalExpression | MemberExpression | ConditionalExpression | + CallExpression | NewExpression | SequenceExpression | TemplateLiteral | + TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | + AwaitExpression | ImportExpression | ChainExpression; + +export interface BaseExpression extends BaseNode { } + +type ChainElement = SimpleCallExpression | MemberExpression; + +export interface ChainExpression extends BaseExpression { + type: "ChainExpression"; + expression: ChainElement; +} + +export interface ThisExpression extends BaseExpression { + type: "ThisExpression"; +} + +export interface ArrayExpression extends BaseExpression { + type: "ArrayExpression"; + elements: Array; +} + +export interface ObjectExpression extends BaseExpression { + type: "ObjectExpression"; + properties: Array; +} + +export interface Property extends BaseNode { + type: "Property"; + key: Expression; + value: Expression | Pattern; // Could be an AssignmentProperty + kind: "init" | "get" | "set"; + method: boolean; + shorthand: boolean; + computed: boolean; +} + +export interface FunctionExpression extends BaseFunction, BaseExpression { + id?: Identifier | null; + type: "FunctionExpression"; + body: BlockStatement; +} + +export interface SequenceExpression extends BaseExpression { + type: "SequenceExpression"; + expressions: Array; +} + +export interface UnaryExpression extends BaseExpression { + type: "UnaryExpression"; + operator: UnaryOperator; + prefix: true; + argument: Expression; +} + +export interface BinaryExpression extends BaseExpression { + type: "BinaryExpression"; + operator: BinaryOperator; + left: Expression; + right: Expression; +} + +export interface AssignmentExpression extends BaseExpression { + type: "AssignmentExpression"; + operator: AssignmentOperator; + left: Pattern | MemberExpression; + right: Expression; +} + +export interface UpdateExpression extends BaseExpression { + type: "UpdateExpression"; + operator: UpdateOperator; + argument: Expression; + prefix: boolean; +} + +export interface LogicalExpression extends BaseExpression { + type: "LogicalExpression"; + operator: LogicalOperator; + left: Expression; + right: Expression; +} + +export interface ConditionalExpression extends BaseExpression { + type: "ConditionalExpression"; + test: Expression; + alternate: Expression; + consequent: Expression; +} + +interface BaseCallExpression extends BaseExpression { + callee: Expression | Super; + arguments: Array; +} +export type CallExpression = SimpleCallExpression | NewExpression; + +export interface SimpleCallExpression extends BaseCallExpression { + type: "CallExpression"; + optional: boolean; +} + +export interface NewExpression extends BaseCallExpression { + type: "NewExpression"; +} + +export interface MemberExpression extends BaseExpression, BasePattern { + type: "MemberExpression"; + object: Expression | Super; + property: Expression; + computed: boolean; + optional: boolean; +} + +export type Pattern = + Identifier | ObjectPattern | ArrayPattern | RestElement | + AssignmentPattern | MemberExpression; + +interface BasePattern extends BaseNode { } + +export interface SwitchCase extends BaseNode { + type: "SwitchCase"; + test?: Expression | null; + consequent: Array; +} + +export interface CatchClause extends BaseNode { + type: "CatchClause"; + param: Pattern | null; + body: BlockStatement; +} + +export interface Identifier extends BaseNode, BaseExpression, BasePattern { + type: "Identifier"; + name: string; +} + +export type Literal = SimpleLiteral | RegExpLiteral; + +export interface SimpleLiteral extends BaseNode, BaseExpression { + type: "Literal"; + value: string | boolean | number | null; + raw?: string; +} + +export interface RegExpLiteral extends BaseNode, BaseExpression { + type: "Literal"; + value?: RegExp | null; + regex: { + pattern: string; + flags: string; + }; + raw?: string; +} + +export type UnaryOperator = + "-" | "+" | "!" | "~" | "typeof" | "void" | "delete"; + +export type BinaryOperator = + "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | + ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "**" | "|" | "^" | "&" | "in" | + "instanceof"; + +export type LogicalOperator = "||" | "&&" | "??"; + +export type AssignmentOperator = + "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "**=" | "<<=" | ">>=" | ">>>=" | + "|=" | "^=" | "&="; + +export type UpdateOperator = "++" | "--"; + +export interface ForOfStatement extends BaseForXStatement { + type: "ForOfStatement"; + await: boolean; +} + +export interface Super extends BaseNode { + type: "Super"; +} + +export interface SpreadElement extends BaseNode { + type: "SpreadElement"; + argument: Expression; +} + +export interface ArrowFunctionExpression extends BaseExpression, BaseFunction { + type: "ArrowFunctionExpression"; + expression: boolean; + body: BlockStatement | Expression; +} + +export interface YieldExpression extends BaseExpression { + type: "YieldExpression"; + argument?: Expression | null; + delegate: boolean; +} + +export interface TemplateLiteral extends BaseExpression { + type: "TemplateLiteral"; + quasis: Array; + expressions: Array; +} + +export interface TaggedTemplateExpression extends BaseExpression { + type: "TaggedTemplateExpression"; + tag: Expression; + quasi: TemplateLiteral; +} + +export interface TemplateElement extends BaseNode { + type: "TemplateElement"; + tail: boolean; + value: { + cooked: string; + raw: string; + }; +} + +export interface AssignmentProperty extends Property { + value: Pattern; + kind: "init"; + method: boolean; // false +} + +export interface ObjectPattern extends BasePattern { + type: "ObjectPattern"; + properties: Array; +} + +export interface ArrayPattern extends BasePattern { + type: "ArrayPattern"; + elements: Array; +} + +export interface RestElement extends BasePattern { + type: "RestElement"; + argument: Pattern; +} + +export interface AssignmentPattern extends BasePattern { + type: "AssignmentPattern"; + left: Pattern; + right: Expression; +} + +export type Class = ClassDeclaration | ClassExpression; +interface BaseClass extends BaseNode { + superClass?: Expression | null; + body: ClassBody; +} + +export interface ClassBody extends BaseNode { + type: "ClassBody"; + body: Array; +} + +export interface MethodDefinition extends BaseNode { + type: "MethodDefinition"; + key: Expression; + value: FunctionExpression; + kind: "constructor" | "method" | "get" | "set"; + computed: boolean; + static: boolean; +} + +export interface ClassDeclaration extends BaseClass, BaseDeclaration { + type: "ClassDeclaration"; + /** It is null when a class declaration is a part of the `export default class` statement */ + id: Identifier | null; +} + +export interface ClassExpression extends BaseClass, BaseExpression { + type: "ClassExpression"; + id?: Identifier | null; +} + +export interface MetaProperty extends BaseExpression { + type: "MetaProperty"; + meta: Identifier; + property: Identifier; +} + +export type ModuleDeclaration = + ImportDeclaration | ExportNamedDeclaration | ExportDefaultDeclaration | + ExportAllDeclaration; +interface BaseModuleDeclaration extends BaseNode { } + +export type ModuleSpecifier = + ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | + ExportSpecifier; +interface BaseModuleSpecifier extends BaseNode { + local: Identifier; +} + +export interface ImportDeclaration extends BaseModuleDeclaration { + type: "ImportDeclaration"; + specifiers: Array; + source: Literal; +} + +export interface ImportSpecifier extends BaseModuleSpecifier { + type: "ImportSpecifier"; + imported: Identifier; +} + +export interface ImportExpression extends BaseExpression { + type: "ImportExpression"; + source: Expression; +} + +export interface ImportDefaultSpecifier extends BaseModuleSpecifier { + type: "ImportDefaultSpecifier"; +} + +export interface ImportNamespaceSpecifier extends BaseModuleSpecifier { + type: "ImportNamespaceSpecifier"; +} + +export interface ExportNamedDeclaration extends BaseModuleDeclaration { + type: "ExportNamedDeclaration"; + declaration?: Declaration | null; + specifiers: Array; + source?: Literal | null; +} + +export interface ExportSpecifier extends BaseModuleSpecifier { + type: "ExportSpecifier"; + exported: Identifier; +} + +export interface ExportDefaultDeclaration extends BaseModuleDeclaration { + type: "ExportDefaultDeclaration"; + declaration: Declaration | Expression; +} + +export interface ExportAllDeclaration extends BaseModuleDeclaration { + type: "ExportAllDeclaration"; + source: Literal; +} + +export interface AwaitExpression extends BaseExpression { + type: "AwaitExpression"; + argument: Expression; +} \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/estree.kt b/kmath-ast/src/jsMain/kotlin/estree.kt new file mode 100644 index 000000000..841688f6d --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/estree.kt @@ -0,0 +1,647 @@ +@file:Suppress( + "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", + "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "ClassName", +) + +import kotlin.js.RegExp + +external interface BaseNodeWithoutComments { + var type: String + var loc: SourceLocation? + get() = definedExternally + set(value) = definedExternally + var range: dynamic /* JsTuple */ + get() = definedExternally + set(value) = definedExternally +} + +external interface BaseNode : BaseNodeWithoutComments { + var leadingComments: Array? + get() = definedExternally + set(value) = definedExternally + var trailingComments: Array? + get() = definedExternally + set(value) = definedExternally +} + +external interface Comment : BaseNodeWithoutComments { + override var type: String /* "Line" | "Block" */ + var value: String +} + +external interface SourceLocation { + var source: String? + get() = definedExternally + set(value) = definedExternally + var start: Position + var end: Position +} + +external interface Position { + var line: Number + var column: Number +} + +external interface Program : BaseNode { + override var type: String /* "Program" */ + var sourceType: String /* "script" | "module" */ + var body: Array + var comments: Array? + get() = definedExternally + set(value) = definedExternally +} + +external interface Directive : BaseNode { + override var type: String /* "ExpressionStatement" */ + var expression: dynamic /* SimpleLiteral | RegExpLiteral */ + get() = definedExternally + set(value) = definedExternally + var directive: String +} + +external interface BaseFunction : BaseNode { + var params: Array + var generator: Boolean? + get() = definedExternally + set(value) = definedExternally + var async: Boolean? + get() = definedExternally + set(value) = definedExternally + var body: dynamic /* BlockStatement | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface BaseStatement : BaseNode + +external interface EmptyStatement : BaseStatement { + override var type: String /* "EmptyStatement" */ +} + +external interface BlockStatement : BaseStatement { + override var type: String /* "BlockStatement" */ + var body: Array + var innerComments: Array? + get() = definedExternally + set(value) = definedExternally +} + +external interface ExpressionStatement : BaseStatement { + override var type: String /* "ExpressionStatement" */ + var expression: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface IfStatement : BaseStatement { + override var type: String /* "IfStatement" */ + var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var consequent: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ + get() = definedExternally + set(value) = definedExternally + var alternate: dynamic /* ExpressionStatement? | BlockStatement? | EmptyStatement? | DebuggerStatement? | WithStatement? | ReturnStatement? | LabeledStatement? | BreakStatement? | ContinueStatement? | IfStatement? | SwitchStatement? | ThrowStatement? | TryStatement? | WhileStatement? | DoWhileStatement? | ForStatement? | ForInStatement? | ForOfStatement? | FunctionDeclaration? | VariableDeclaration? | ClassDeclaration? */ + get() = definedExternally + set(value) = definedExternally +} + +external interface LabeledStatement : BaseStatement { + override var type: String /* "LabeledStatement" */ + var label: Identifier + var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ + get() = definedExternally + set(value) = definedExternally +} + +external interface BreakStatement : BaseStatement { + override var type: String /* "BreakStatement" */ + var label: Identifier? + get() = definedExternally + set(value) = definedExternally +} + +external interface ContinueStatement : BaseStatement { + override var type: String /* "ContinueStatement" */ + var label: Identifier? + get() = definedExternally + set(value) = definedExternally +} + +external interface WithStatement : BaseStatement { + override var type: String /* "WithStatement" */ + var `object`: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ + get() = definedExternally + set(value) = definedExternally +} + +external interface SwitchStatement : BaseStatement { + override var type: String /* "SwitchStatement" */ + var discriminant: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var cases: Array +} + +external interface ReturnStatement : BaseStatement { + override var type: String /* "ReturnStatement" */ + var argument: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ThrowStatement : BaseStatement { + override var type: String /* "ThrowStatement" */ + var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface TryStatement : BaseStatement { + override var type: String /* "TryStatement" */ + var block: BlockStatement + var handler: CatchClause? + get() = definedExternally + set(value) = definedExternally + var finalizer: BlockStatement? + get() = definedExternally + set(value) = definedExternally +} + +external interface WhileStatement : BaseStatement { + override var type: String /* "WhileStatement" */ + var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ + get() = definedExternally + set(value) = definedExternally +} + +external interface DoWhileStatement : BaseStatement { + override var type: String /* "DoWhileStatement" */ + var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ + get() = definedExternally + set(value) = definedExternally + var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ForStatement : BaseStatement { + override var type: String /* "ForStatement" */ + var init: dynamic /* VariableDeclaration? | ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ + get() = definedExternally + set(value) = definedExternally + var test: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ + get() = definedExternally + set(value) = definedExternally + var update: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ + get() = definedExternally + set(value) = definedExternally + var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ + get() = definedExternally + set(value) = definedExternally +} + +external interface BaseForXStatement : BaseStatement { + var left: dynamic /* VariableDeclaration | Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ + get() = definedExternally + set(value) = definedExternally + var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ForInStatement : BaseForXStatement { + override var type: String /* "ForInStatement" */ +} + +external interface DebuggerStatement : BaseStatement { + override var type: String /* "DebuggerStatement" */ +} + +external interface BaseDeclaration : BaseStatement + +external interface FunctionDeclaration : BaseFunction, BaseDeclaration { + override var type: String /* "FunctionDeclaration" */ + var id: Identifier? + override var body: BlockStatement +} + +external interface VariableDeclaration : BaseDeclaration { + override var type: String /* "VariableDeclaration" */ + var declarations: Array + var kind: String /* "var" | "let" | "const" */ +} + +external interface VariableDeclarator : BaseNode { + override var type: String /* "VariableDeclarator" */ + var id: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ + get() = definedExternally + set(value) = definedExternally + var init: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ + get() = definedExternally + set(value) = definedExternally +} + +external interface BaseExpression : BaseNode + +external interface ChainExpression : BaseExpression { + override var type: String /* "ChainExpression" */ + var expression: dynamic /* SimpleCallExpression | MemberExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ThisExpression : BaseExpression { + override var type: String /* "ThisExpression" */ +} + +external interface ArrayExpression : BaseExpression { + override var type: String /* "ArrayExpression" */ + var elements: Array +} + +external interface ObjectExpression : BaseExpression { + override var type: String /* "ObjectExpression" */ + var properties: Array +} + +external interface Property : BaseNode { + override var type: String /* "Property" */ + var key: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var value: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern */ + get() = definedExternally + set(value) = definedExternally + var kind: String /* "init" | "get" | "set" */ + var method: Boolean + var shorthand: Boolean + var computed: Boolean +} + +external interface FunctionExpression : BaseFunction, BaseExpression { + var id: Identifier? + get() = definedExternally + set(value) = definedExternally + override var type: String /* "FunctionExpression" */ + override var body: BlockStatement +} + +external interface SequenceExpression : BaseExpression { + override var type: String /* "SequenceExpression" */ + var expressions: Array +} + +external interface UnaryExpression : BaseExpression { + override var type: String /* "UnaryExpression" */ + var operator: String /* "-" | "+" | "!" | "~" | "typeof" | "void" | "delete" */ + var prefix: Boolean + var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface BinaryExpression : BaseExpression { + override var type: String /* "BinaryExpression" */ + var operator: String /* "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "**" | "|" | "^" | "&" | "in" | "instanceof" */ + var left: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface AssignmentExpression : BaseExpression { + override var type: String /* "AssignmentExpression" */ + var operator: String /* "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "**=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=" */ + var left: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ + get() = definedExternally + set(value) = definedExternally + var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface UpdateExpression : BaseExpression { + override var type: String /* "UpdateExpression" */ + var operator: String /* "++" | "--" */ + var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var prefix: Boolean +} + +external interface LogicalExpression : BaseExpression { + override var type: String /* "LogicalExpression" */ + var operator: String /* "||" | "&&" | "??" */ + var left: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ConditionalExpression : BaseExpression { + override var type: String /* "ConditionalExpression" */ + var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var alternate: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var consequent: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface BaseCallExpression : BaseExpression { + var callee: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | Super */ + get() = definedExternally + set(value) = definedExternally + var arguments: Array +} + +external interface SimpleCallExpression : BaseCallExpression { + override var type: String /* "CallExpression" */ + var optional: Boolean +} + +external interface NewExpression : BaseCallExpression { + override var type: String /* "NewExpression" */ +} + +external interface MemberExpression : BaseExpression, BasePattern { + override var type: String /* "MemberExpression" */ + var `object`: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | Super */ + get() = definedExternally + set(value) = definedExternally + var property: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var computed: Boolean + var optional: Boolean +} + +external interface BasePattern : BaseNode + +external interface SwitchCase : BaseNode { + override var type: String /* "SwitchCase" */ + var test: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ + get() = definedExternally + set(value) = definedExternally + var consequent: Array +} + +external interface CatchClause : BaseNode { + override var type: String /* "CatchClause" */ + var param: dynamic /* Identifier? | ObjectPattern? | ArrayPattern? | RestElement? | AssignmentPattern? | MemberExpression? */ + get() = definedExternally + set(value) = definedExternally + var body: BlockStatement +} + +external interface Identifier : BaseNode, BaseExpression, BasePattern { + override var type: String /* "Identifier" */ + var name: String +} + +external interface SimpleLiteral : BaseNode, BaseExpression { + override var type: String /* "Literal" */ + var value: dynamic /* String? | Boolean? | Number? */ + get() = definedExternally + set(value) = definedExternally + var raw: String? + get() = definedExternally + set(value) = definedExternally +} + +external interface `T$1` { + var pattern: String + var flags: String +} + +external interface RegExpLiteral : BaseNode, BaseExpression { + override var type: String /* "Literal" */ + var value: RegExp? + get() = definedExternally + set(value) = definedExternally + var regex: `T$1` + var raw: String? + get() = definedExternally + set(value) = definedExternally +} + +external interface ForOfStatement : BaseForXStatement { + override var type: String /* "ForOfStatement" */ + var await: Boolean +} + +external interface Super : BaseNode { + override var type: String /* "Super" */ +} + +external interface SpreadElement : BaseNode { + override var type: String /* "SpreadElement" */ + var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ArrowFunctionExpression : BaseExpression, BaseFunction { + override var type: String /* "ArrowFunctionExpression" */ + var expression: Boolean + override var body: dynamic /* BlockStatement | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface YieldExpression : BaseExpression { + override var type: String /* "YieldExpression" */ + var argument: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ + get() = definedExternally + set(value) = definedExternally + var delegate: Boolean +} + +external interface TemplateLiteral : BaseExpression { + override var type: String /* "TemplateLiteral" */ + var quasis: Array + var expressions: Array +} + +external interface TaggedTemplateExpression : BaseExpression { + override var type: String /* "TaggedTemplateExpression" */ + var tag: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var quasi: TemplateLiteral +} + +external interface `T$2` { + var cooked: String + var raw: String +} + +external interface TemplateElement : BaseNode { + override var type: String /* "TemplateElement" */ + var tail: Boolean + var value: `T$2` +} + +external interface AssignmentProperty : Property { + override var value: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ + get() = definedExternally + set(value) = definedExternally + override var kind: String /* "init" */ + override var method: Boolean +} + +external interface ObjectPattern : BasePattern { + override var type: String /* "ObjectPattern" */ + var properties: Array +} + +external interface ArrayPattern : BasePattern { + override var type: String /* "ArrayPattern" */ + var elements: Array +} + +external interface RestElement : BasePattern { + override var type: String /* "RestElement" */ + var argument: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface AssignmentPattern : BasePattern { + override var type: String /* "AssignmentPattern" */ + var left: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ + get() = definedExternally + set(value) = definedExternally + var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface BaseClass : BaseNode { + var superClass: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ + get() = definedExternally + set(value) = definedExternally + var body: ClassBody +} + +external interface ClassBody : BaseNode { + override var type: String /* "ClassBody" */ + var body: Array +} + +external interface MethodDefinition : BaseNode { + override var type: String /* "MethodDefinition" */ + var key: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally + var value: FunctionExpression + var kind: String /* "constructor" | "method" | "get" | "set" */ + var computed: Boolean + var static: Boolean +} + +external interface ClassDeclaration : BaseClass, BaseDeclaration { + override var type: String /* "ClassDeclaration" */ + var id: Identifier? +} + +external interface ClassExpression : BaseClass, BaseExpression { + override var type: String /* "ClassExpression" */ + var id: Identifier? + get() = definedExternally + set(value) = definedExternally +} + +external interface MetaProperty : BaseExpression { + override var type: String /* "MetaProperty" */ + var meta: Identifier + var property: Identifier +} + +external interface BaseModuleDeclaration : BaseNode + +external interface BaseModuleSpecifier : BaseNode { + var local: Identifier +} + +external interface ImportDeclaration : BaseModuleDeclaration { + override var type: String /* "ImportDeclaration" */ + var specifiers: Array + var source: dynamic /* SimpleLiteral | RegExpLiteral */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ImportSpecifier : BaseModuleSpecifier { + override var type: String /* "ImportSpecifier" */ + var imported: Identifier +} + +external interface ImportExpression : BaseExpression { + override var type: String /* "ImportExpression" */ + var source: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ImportDefaultSpecifier : BaseModuleSpecifier { + override var type: String /* "ImportDefaultSpecifier" */ +} + +external interface ImportNamespaceSpecifier : BaseModuleSpecifier { + override var type: String /* "ImportNamespaceSpecifier" */ +} + +external interface ExportNamedDeclaration : BaseModuleDeclaration { + override var type: String /* "ExportNamedDeclaration" */ + var declaration: dynamic /* FunctionDeclaration? | VariableDeclaration? | ClassDeclaration? */ + get() = definedExternally + set(value) = definedExternally + var specifiers: Array + var source: dynamic /* SimpleLiteral? | RegExpLiteral? */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ExportSpecifier : BaseModuleSpecifier { + override var type: String /* "ExportSpecifier" */ + var exported: Identifier +} + +external interface ExportDefaultDeclaration : BaseModuleDeclaration { + override var type: String /* "ExportDefaultDeclaration" */ + var declaration: dynamic /* FunctionDeclaration | VariableDeclaration | ClassDeclaration | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} + +external interface ExportAllDeclaration : BaseModuleDeclaration { + override var type: String /* "ExportAllDeclaration" */ + var source: dynamic /* SimpleLiteral | RegExpLiteral */ + get() = definedExternally + set(value) = definedExternally +} + +external interface AwaitExpression : BaseExpression { + override var type: String /* "AwaitExpression" */ + var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ + get() = definedExternally + set(value) = definedExternally +} \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt new file mode 100644 index 000000000..fd548b72b --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt @@ -0,0 +1,40 @@ +@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS") +package tsstdlib + +import kotlin.js.* +import org.khronos.webgl.* +import org.w3c.dom.* +import org.w3c.dom.events.* +import org.w3c.dom.parsing.* +import org.w3c.dom.svg.* +import org.w3c.dom.url.* +import org.w3c.fetch.* +import org.w3c.files.* +import org.w3c.notifications.* +import org.w3c.performance.* +import org.w3c.workers.* +import org.w3c.xhr.* + +external interface IteratorYieldResult { + var done: Boolean? + get() = definedExternally + set(value) = definedExternally + var value: TYield +} + +external interface IteratorReturnResult { + var done: Boolean + var value: TReturn +} + +external interface Iterator { + fun next(vararg args: Any /* JsTuple<> | JsTuple */): dynamic /* IteratorYieldResult | IteratorReturnResult */ + val `return`: ((value: TReturn) -> dynamic)? + val `throw`: ((e: Any) -> dynamic)? +} + +typealias Iterator__1 = Iterator + +external interface Iterable + +external interface IterableIterator : Iterator__1 \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/lib.es5.kt b/kmath-ast/src/jsMain/kotlin/lib.es5.kt new file mode 100644 index 000000000..fe3847232 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/lib.es5.kt @@ -0,0 +1,86 @@ +@file:Suppress( + "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", + "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "DEPRECATION", "PackageDirectoryMismatch", "KDocMissingDocumentation", + "PropertyName" +) + +package tsstdlib + +import kotlin.js.RegExp + +typealias RegExpMatchArray = Array + +typealias RegExpExecArray = Array + +external interface RegExpConstructor { + @nativeInvoke + operator fun invoke(pattern: RegExp, flags: String = definedExternally): RegExp + + @nativeInvoke + operator fun invoke(pattern: RegExp): RegExp + + @nativeInvoke + operator fun invoke(pattern: String, flags: String = definedExternally): RegExp + + @nativeInvoke + operator fun invoke(pattern: String): RegExp + var prototype: RegExp + var `$1`: String + var `$2`: String + var `$3`: String + var `$4`: String + var `$5`: String + var `$6`: String + var `$7`: String + var `$8`: String + var `$9`: String + var lastMatch: String +} + +external interface ConcatArray { + var length: Number + + @nativeGetter + operator fun get(n: Number): T? + + @nativeSetter + operator fun set(n: Number, value: T) + fun join(separator: String = definedExternally): String + fun slice(start: Number = definedExternally, end: Number = definedExternally): Array +} + +external interface ArrayConstructor { + fun from(iterable: Iterable): Array + fun from(iterable: ArrayLike): Array + fun from(iterable: Iterable, mapfn: (v: T, k: Number) -> U, thisArg: Any = definedExternally): Array + fun from(iterable: Iterable, mapfn: (v: T, k: Number) -> U): Array + fun from(iterable: ArrayLike, mapfn: (v: T, k: Number) -> U, thisArg: Any = definedExternally): Array + fun from(iterable: ArrayLike, mapfn: (v: T, k: Number) -> U): Array + fun of(vararg items: T): Array + + @nativeInvoke + operator fun invoke(arrayLength: Number = definedExternally): Array + + @nativeInvoke + operator fun invoke(): Array + + @nativeInvoke + operator fun invoke(arrayLength: Number): Array + + @nativeInvoke + operator fun invoke(vararg items: T): Array + fun isArray(arg: Any): Boolean + var prototype: Array +} + +external interface ArrayLike { + var length: Number + + @nativeGetter + operator fun get(n: Number): T? + + @nativeSetter + operator fun set(n: Number, value: T) +} + +typealias Extract = Any \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/stream.d.ts b/kmath-ast/src/jsMain/kotlin/stream.d.ts new file mode 100644 index 000000000..f98fcab8c --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/stream.d.ts @@ -0,0 +1,5 @@ +import {Emitter} from 'emitter' + +export class Stream extends Emitter { + pipe(dest: any, options: any): any +} diff --git a/kmath-ast/src/jsMain/kotlin/stream.kt b/kmath-ast/src/jsMain/kotlin/stream.kt new file mode 100644 index 000000000..d76f43f71 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/stream.kt @@ -0,0 +1,9 @@ +@file:Suppress( + "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", + "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "SortModifiers", + "KDocMissingDocumentation" +) + +external open class Stream : Emitter { + open fun pipe(dest: Any, options: Any): Any +} \ No newline at end of file From d66fb4be750e92c3f022e32be1338c743fdb1ac4 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 00:56:08 +0700 Subject: [PATCH 08/55] Delete empty file --- kmath-ast/src/jsMain/kotlin/Codegen.kt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 kmath-ast/src/jsMain/kotlin/Codegen.kt diff --git a/kmath-ast/src/jsMain/kotlin/Codegen.kt b/kmath-ast/src/jsMain/kotlin/Codegen.kt deleted file mode 100644 index e69de29bb..000000000 From 32d77c0e7f4868725c54d05fd99da783ffb8dec5 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 17:42:57 +0700 Subject: [PATCH 09/55] Implement ESTree based code generation for the MST --- kmath-ast/build.gradle.kts | 14 +++ kmath-ast/src/jsMain/kotlin/astring.global.kt | 2 +- kmath-ast/src/jsMain/kotlin/astring.kt | 16 +++- .../src/jsMain/kotlin/astring.typealises.kt | 3 + kmath-ast/src/jsMain/kotlin/emitter.d.ts | 3 - kmath-ast/src/jsMain/kotlin/emitter.kt | 5 +- .../src/jsMain/kotlin/estree.extensions.kt | 67 +++++++++++++ kmath-ast/src/jsMain/kotlin/estree.kt | 4 +- .../kotlin/kscience/kmath/estree/Codegen.kt | 78 +++++++++++++++ .../kmath/estree/internal/JSBuilder.kt | 73 ++++++++++++++ .../src/jsMain/kotlin/lib.es2015.iterable.kt | 18 +--- kmath-ast/src/jsMain/kotlin/stream.kt | 6 +- .../kmath/estree/TestESTreeAlgebras.kt | 94 +++++++++++++++++++ .../kmath/estree/TestESTreeExpressions.kt | 56 +++++++++++ .../kmath/estree/TestESTreeSpecialization.kt | 54 +++++++++++ .../kmath/estree/TestESTreeVariables.kt | 22 +++++ .../kscience/kmath/asm/internal/AsmBuilder.kt | 2 +- .../kscience/kmath/asm/TestAsmVariables.kt | 4 +- 18 files changed, 491 insertions(+), 30 deletions(-) create mode 100644 kmath-ast/src/jsMain/kotlin/astring.typealises.kt create mode 100644 kmath-ast/src/jsMain/kotlin/estree.extensions.kt create mode 100644 kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt create mode 100644 kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt create mode 100644 kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeAlgebras.kt create mode 100644 kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeExpressions.kt create mode 100644 kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt create mode 100644 kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index e3884025d..1f4a87b12 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -2,6 +2,20 @@ plugins { id("ru.mipt.npm.mpp") } +kotlin.js { + nodejs { + testTask { + useMocha().timeout = "0" + } + } + + browser { + testTask { + useMocha().timeout = "0" + } + } +} + kotlin.sourceSets { commonMain { dependencies { diff --git a/kmath-ast/src/jsMain/kotlin/astring.global.kt b/kmath-ast/src/jsMain/kotlin/astring.global.kt index 78c771f26..c69c26caf 100644 --- a/kmath-ast/src/jsMain/kotlin/astring.global.kt +++ b/kmath-ast/src/jsMain/kotlin/astring.global.kt @@ -10,7 +10,7 @@ import Generator @Suppress("EXTERNAL_DELEGATION", "NESTED_CLASS_IN_EXTERNAL_INTERFACE") external interface astring { - var generate: Any + var generate: (dynamic, dynamic) -> dynamic var baseGenerator: Generator companion object : astring by definedExternally diff --git a/kmath-ast/src/jsMain/kotlin/astring.kt b/kmath-ast/src/jsMain/kotlin/astring.kt index e9ab6f627..fe2b2da0a 100644 --- a/kmath-ast/src/jsMain/kotlin/astring.kt +++ b/kmath-ast/src/jsMain/kotlin/astring.kt @@ -1,7 +1,15 @@ -@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation" +@file:Suppress( + "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", + "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "PackageDirectoryMismatch" ) +@file:JsModule("astring") +@file:JsNonModule +package astring + +import Generator +import estree.BaseNode + external interface Options { var indent: String? get() = definedExternally @@ -27,6 +35,4 @@ external fun generate(node: BaseNode, options: Options /* Options & `T$0` */ = d external fun generate(node: BaseNode): String -typealias Generator = Any - -external var baseGenerator: Generator \ No newline at end of file +external var baseGenerator: Generator diff --git a/kmath-ast/src/jsMain/kotlin/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/astring.typealises.kt new file mode 100644 index 000000000..9b74e2d04 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/astring.typealises.kt @@ -0,0 +1,3 @@ +@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation") + +typealias Generator = Any diff --git a/kmath-ast/src/jsMain/kotlin/emitter.d.ts b/kmath-ast/src/jsMain/kotlin/emitter.d.ts index ea0319cd6..4970529d4 100644 --- a/kmath-ast/src/jsMain/kotlin/emitter.d.ts +++ b/kmath-ast/src/jsMain/kotlin/emitter.d.ts @@ -14,6 +14,3 @@ export class Emitter { hasListeners(event: string): boolean } - - -function mixin(obj: any): any diff --git a/kmath-ast/src/jsMain/kotlin/emitter.kt b/kmath-ast/src/jsMain/kotlin/emitter.kt index ad0a16bf7..94398397f 100644 --- a/kmath-ast/src/jsMain/kotlin/emitter.kt +++ b/kmath-ast/src/jsMain/kotlin/emitter.kt @@ -2,9 +2,12 @@ "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "CONFLICTING_OVERLOADS", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "SortModifiers" + "CONFLICTING_OVERLOADS", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "SortModifiers", + "PackageDirectoryMismatch" ) +package emitter + external open class Emitter { constructor(obj: Any) constructor() diff --git a/kmath-ast/src/jsMain/kotlin/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/estree.extensions.kt new file mode 100644 index 000000000..d4fc4baa1 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/estree.extensions.kt @@ -0,0 +1,67 @@ +@file:Suppress( + "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", + "NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING", "PackageDirectoryMismatch" +) + +package estree + +fun Program(sourceType: String, vararg body: dynamic) = object : Program { + override var type = "Program" + override var sourceType = sourceType + override var body = body +} + +fun VariableDeclaration(kind: String, vararg declarations: VariableDeclarator) = object : VariableDeclaration { + override var type = "VariableDeclaration" + override var declarations = declarations.toList().toTypedArray() + override var kind = kind +} + +fun VariableDeclarator(id: dynamic, init: dynamic) = object : VariableDeclarator { + override var type = "VariableDeclarator" + override var id = id + override var init = init +} + +fun Identifier(name: String) = object : Identifier { + override var type = "Identifier" + override var name = name +} + +fun FunctionExpression(params: Array, body: BlockStatement) = object : FunctionExpression { + override var params = params + override var type = "FunctionExpression" + override var body = body +} + +fun BlockStatement(vararg body: dynamic) = object : BlockStatement { + override var type = "BlockStatement" + override var body = body +} + +fun ReturnStatement(argument: dynamic) = object : ReturnStatement { + override var type = "ReturnStatement" + override var argument = argument +} + +fun SimpleLiteral(value: dynamic) = object : SimpleLiteral { + override var type = "Literal" + override var value = value +} + +fun MemberExpression(computed: Boolean, optional: Boolean, `object`: dynamic, property: dynamic) = + object : MemberExpression { + override var type = "MemberExpression" + override var computed = computed + override var optional = optional + override var `object` = `object` + override var property = property + } + +fun SimpleCallExpression(optional: Boolean, callee: dynamic, vararg arguments: dynamic) = + object : SimpleCallExpression { + override var type = "CallExpression" + override var optional = optional + override var callee = callee + override var arguments = arguments + } diff --git a/kmath-ast/src/jsMain/kotlin/estree.kt b/kmath-ast/src/jsMain/kotlin/estree.kt index 841688f6d..79d043eae 100644 --- a/kmath-ast/src/jsMain/kotlin/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/estree.kt @@ -1,8 +1,10 @@ @file:Suppress( "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "ClassName", + "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "ClassName", "PackageDirectoryMismatch", ) +package estree + import kotlin.js.RegExp external interface BaseNodeWithoutComments { diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt new file mode 100644 index 000000000..d10c9c0cf --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt @@ -0,0 +1,78 @@ +package kscience.kmath.estree + +import estree.* +import kscience.kmath.ast.MST +import kscience.kmath.ast.MstExpression +import kscience.kmath.estree.internal.JSBuilder +import kscience.kmath.expressions.Expression +import kscience.kmath.operations.Algebra +import kscience.kmath.operations.NumericAlgebra +import kscience.kmath.operations.RealField + +@PublishedApi +internal fun MST.compileWith(algebra: Algebra): Expression { + fun JSBuilder.visit(node: MST): BaseExpression = when (node) { + is MST.Symbolic -> { + val symbol = try { + algebra.symbol(node.value) + } catch (ignored: IllegalStateException) { + null + } + + if (symbol != null) + constant(symbol) + else + variable(node.value) + } + + is MST.Numeric -> constant(node.value) + is MST.Unary -> call(algebra.unaryOperation(node.operation), visit(node.value)) + + is MST.Binary -> when { + algebra is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> constant( + algebra.number( + RealField + .binaryOperation(node.operation) + .invoke(node.left.value.toDouble(), node.right.value.toDouble()) + ) + ) + + algebra is NumericAlgebra && node.left is MST.Numeric -> call( + algebra.leftSideNumberOperation(node.operation), + visit(node.left), + visit(node.right), + ) + + algebra is NumericAlgebra && node.right is MST.Numeric -> call( + algebra.rightSideNumberOperation(node.operation), + visit(node.left), + visit(node.right), + ) + + else -> call( + algebra.binaryOperation(node.operation), + visit(node.left), + visit(node.right), + ) + } + } + + return JSBuilder { visit(this@compileWith) }.instance +} + + +/** + * Compiles an [MST] to ASM using given algebra. + * + * @author Alexander Nozik. + */ +public fun Algebra.expression(mst: MST): Expression = + mst.compileWith(this) + +/** + * Optimizes performance of an [MstExpression] using ASM codegen. + * + * @author Alexander Nozik. + */ +public fun MstExpression>.compile(): Expression = + mst.compileWith(algebra) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt new file mode 100644 index 000000000..7b3f02616 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt @@ -0,0 +1,73 @@ +package kscience.kmath.estree.internal + +import astring.generate +import estree.* +import kscience.kmath.expressions.Expression +import kscience.kmath.expressions.Symbol + +internal class JSBuilder(val bodyCallback: JSBuilder.() -> BaseExpression) { + private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression { + @Suppress("UNUSED_VARIABLE", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") + override fun invoke(map: Map): T { + val e = executable + val c = constants + val a = js("{}") + map.forEach { (key, value) -> a[key.identity] = value } + return js("e(c, a)").unsafeCast() + } + } + + val instance: Expression by lazy { + val node = Program( + sourceType = "script", + VariableDeclaration( + kind = "var", + VariableDeclarator( + id = Identifier("executable"), + init = FunctionExpression( + params = arrayOf(Identifier("constants"), Identifier("arguments")), + body = BlockStatement(ReturnStatement(bodyCallback())), + ), + ), + ), + ) + + eval(generate(node)) + GeneratedExpression(js("executable"), constants.toTypedArray()) + } + + private val constants = mutableListOf() + private val keys = mutableListOf() + + fun constant(value: Any?) = when { + value == null || jsTypeOf(value) == "number" || jsTypeOf(value) == "string" || jsTypeOf(value) == "boolean" -> { + SimpleLiteral(value) + } + + else -> { + val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex + + MemberExpression( + computed = true, + optional = false, + `object` = Identifier("constants"),я + property = SimpleLiteral(idx), + ) + } + } + + fun variable(name: String): BaseExpression { + return MemberExpression( + computed = true, + optional = false, + `object` = Identifier("arguments"), + property = SimpleLiteral(name), + ) + } + + fun call(function: Function, vararg args: BaseExpression): BaseExpression = SimpleCallExpression( + optional = false, + callee = constant(function), + *args, + ) +} diff --git a/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt index fd548b72b..b55785a8e 100644 --- a/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt +++ b/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt @@ -1,20 +1,8 @@ -@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS") +@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", + "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "PackageDirectoryMismatch" +) package tsstdlib -import kotlin.js.* -import org.khronos.webgl.* -import org.w3c.dom.* -import org.w3c.dom.events.* -import org.w3c.dom.parsing.* -import org.w3c.dom.svg.* -import org.w3c.dom.url.* -import org.w3c.fetch.* -import org.w3c.files.* -import org.w3c.notifications.* -import org.w3c.performance.* -import org.w3c.workers.* -import org.w3c.xhr.* - external interface IteratorYieldResult { var done: Boolean? get() = definedExternally diff --git a/kmath-ast/src/jsMain/kotlin/stream.kt b/kmath-ast/src/jsMain/kotlin/stream.kt index d76f43f71..c6c30446c 100644 --- a/kmath-ast/src/jsMain/kotlin/stream.kt +++ b/kmath-ast/src/jsMain/kotlin/stream.kt @@ -1,9 +1,13 @@ @file:Suppress( "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "SortModifiers", - "KDocMissingDocumentation" + "KDocMissingDocumentation", "PackageDirectoryMismatch" ) +package stream + +import emitter.Emitter + external open class Stream : Emitter { open fun pipe(dest: Any, options: Any): Any } \ No newline at end of file diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeAlgebras.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeAlgebras.kt new file mode 100644 index 000000000..09a8ab3e5 --- /dev/null +++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeAlgebras.kt @@ -0,0 +1,94 @@ +package kscience.kmath.estree + +import kscience.kmath.ast.mstInField +import kscience.kmath.ast.mstInRing +import kscience.kmath.ast.mstInSpace +import kscience.kmath.expressions.invoke +import kscience.kmath.operations.ByteRing +import kscience.kmath.operations.RealField +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class TestESTreeAlgebras { + @Test + fun space() { + val res1 = ByteRing.mstInSpace { + binaryOperation("+")( + unaryOperation("+")( + number(3.toByte()) - (number(2.toByte()) + (multiply( + add(number(1), number(1)), + 2 + ) + number(1.toByte()) * 3.toByte() - number(1.toByte()))) + ), + + number(1) + ) + symbol("x") + zero + }("x" to 2.toByte()) + + val res2 = ByteRing.mstInSpace { + binaryOperation("+")( + unaryOperation("+")( + number(3.toByte()) - (number(2.toByte()) + (multiply( + add(number(1), number(1)), + 2 + ) + number(1.toByte()) * 3.toByte() - number(1.toByte()))) + ), + + number(1) + ) + symbol("x") + zero + }.compile()("x" to 2.toByte()) + + assertEquals(res1, res2) + } + + @Test + fun ring() { + val res1 = ByteRing.mstInRing { + binaryOperation("+")( + unaryOperation("+")( + (symbol("x") - (2.toByte() + (multiply( + add(number(1), number(1)), + 2 + ) + 1.toByte()))) * 3.0 - 1.toByte() + ), + + number(1) + ) * number(2) + }("x" to 3.toByte()) + + val res2 = ByteRing.mstInRing { + binaryOperation("+")( + unaryOperation("+")( + (symbol("x") - (2.toByte() + (multiply( + add(number(1), number(1)), + 2 + ) + 1.toByte()))) * 3.0 - 1.toByte() + ), + number(1) + ) * number(2) + }.compile()("x" to 3.toByte()) + + assertEquals(res1, res2) + } + + @Test + fun field() { + val res1 = RealField.mstInField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + }("x" to 2.0) + + val res2 = RealField.mstInField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + }.compile()("x" to 2.0) + + assertEquals(res1, res2) + } +} diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeExpressions.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeExpressions.kt new file mode 100644 index 000000000..3dc259cb3 --- /dev/null +++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeExpressions.kt @@ -0,0 +1,56 @@ +package kscience.kmath.estree + +import kscience.kmath.ast.mstInExtendedField +import kscience.kmath.ast.mstInField +import kscience.kmath.ast.mstInSpace +import kscience.kmath.expressions.Expression +import kscience.kmath.expressions.StringSymbol +import kscience.kmath.expressions.invoke +import kscience.kmath.operations.RealField +import kotlin.math.pow +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.time.measureTime + +internal class TestESTreeExpressions { + @Test + fun testUnaryOperationInvocation() { + val expression = RealField.mstInSpace { -symbol("x") }.compile() + val res = expression("x" to 2.0) + assertEquals(-2.0, res) + } + + @Test + fun testBinaryOperationInvocation() { + val expression = RealField.mstInSpace { -symbol("x") + number(1.0) }.compile() + val res = expression("x" to 2.0) + assertEquals(-1.0, res) + } + + @Test + fun testConstProductInvocation() { + val res = RealField.mstInField { symbol("x") * 2 }("x" to 2.0) + assertEquals(4.0, res) + } + + @Test + fun testMultipleCalls() { + val e1 = + RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile() + + val e2 = Expression { a -> + val x = a.getValue(StringSymbol("x")) + kotlin.math.sin(x).pow(4) - 6 * x / kotlin.math.tanh(x) + } + + var r = Random(0) + var s = 0.0 + measureTime { repeat(1000000) { s += e1("x" to r.nextDouble()) } }.also(::println) + println(s) + s = 0.0 + r = Random(0) + measureTime { repeat(1000000) { s += e2("x" to r.nextDouble()) } }.also(::println) + println(s) + } +} diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt new file mode 100644 index 000000000..0821686fc --- /dev/null +++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt @@ -0,0 +1,54 @@ +package kscience.kmath.estree + +import kscience.kmath.ast.mstInField +import kscience.kmath.expressions.invoke +import kscience.kmath.operations.RealField +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class TestESTreeSpecialization { + @Test + fun testUnaryPlus() { + val expr = RealField.mstInField { unaryOperation("+")(symbol("x")) }.compile() + assertEquals(2.0, expr("x" to 2.0)) + } + + @Test + fun testUnaryMinus() { + val expr = RealField.mstInField { unaryOperation("-")(symbol("x")) }.compile() + assertEquals(-2.0, expr("x" to 2.0)) + } + + @Test + fun testAdd() { + val expr = RealField.mstInField { binaryOperation("+")(symbol("x"), symbol("x")) }.compile() + assertEquals(4.0, expr("x" to 2.0)) + } + + @Test + fun testSine() { + val expr = RealField.mstInField { unaryOperation("sin")(symbol("x")) }.compile() + assertEquals(0.0, expr("x" to 0.0)) + } + + @Test + fun testMinus() { + val expr = RealField.mstInField { binaryOperation("-")(symbol("x"), symbol("x")) }.compile() + assertEquals(0.0, expr("x" to 2.0)) + } + + @Test + fun testDivide() { + val expr = RealField.mstInField { binaryOperation("/")(symbol("x"), symbol("x")) }.compile() + assertEquals(1.0, expr("x" to 2.0)) + } + + @Test + fun testPower() { + val expr = RealField + .mstInField { binaryOperation("pow")(symbol("x"), number(2)) } + .compile() + + assertEquals(4.0, expr("x" to 2.0)) + } +} diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt new file mode 100644 index 000000000..b6f59247d --- /dev/null +++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt @@ -0,0 +1,22 @@ +package kscience.kmath.estree + +import kscience.kmath.ast.mstInRing +import kscience.kmath.expressions.invoke +import kscience.kmath.operations.ByteRing +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +internal class TestESTreeVariables { + @Test + fun testVariableWithoutDefault() { + val expr = ByteRing.mstInRing { symbol("x") }.compile() + assertEquals(1.toByte(), expr("x" to 1.toByte())) + } + + @Test + fun testVariableWithoutDefaultFails() { + val expr = ByteRing.mstInRing { symbol("x") }.compile() + assertFailsWith { expr() } + } +} 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 d146afeee..20e42ed25 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 @@ -274,7 +274,7 @@ internal class AsmBuilder( inline fun buildCall(function: Function, parameters: AsmBuilder.() -> Unit) { contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } - val `interface` = function.javaClass.interfaces.first { it.interfaces.contains(Function::class.java) } + val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces } val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount ?: error("Provided function object doesn't contain invoke method") diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt index 1011515c8..0ebc31be4 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt @@ -10,13 +10,13 @@ import kotlin.test.assertFailsWith internal class TestAsmVariables { @Test fun testVariableWithoutDefault() { - val expr = ByteRing.mstInRing { symbol("x") } + val expr = ByteRing.mstInRing { symbol("x") }.compile() assertEquals(1.toByte(), expr("x" to 1.toByte())) } @Test fun testVariableWithoutDefaultFails() { - val expr = ByteRing.mstInRing { symbol("x") } + val expr = ByteRing.mstInRing { symbol("x") }.compile() assertFailsWith { expr() } } } From a655404486d5cebef9e8c52c2a0c0e69e394dda3 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 17:43:21 +0700 Subject: [PATCH 10/55] Fix typo --- .../jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt index 7b3f02616..b6b58179b 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt @@ -50,7 +50,7 @@ internal class JSBuilder(val bodyCallback: JSBuilder.() -> BaseExpression) MemberExpression( computed = true, optional = false, - `object` = Identifier("constants"),я + `object` = Identifier("constants"), property = SimpleLiteral(idx), ) } From de3c2a1b5ad902c1b6bba70a4983b033ae822924 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 20 Dec 2020 14:18:12 +0300 Subject: [PATCH 11/55] Add curring and update kotlin --- .../kscience/kmath/operations/Algebra.kt | 28 +++++++++++++++++++ settings.gradle.kts | 4 +-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index 12a45615a..ed10901df 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -22,10 +22,22 @@ public interface Algebra { */ public fun unaryOperation(operation: String, arg: T): T + /** + * Currying version of [unaryOperation] + */ + public fun unaryOperationFunction(operation: String): (T) -> T = { unaryOperation(operation, it) } + /** * Dynamic call of binary operation [operation] on [left] and [right] */ public fun binaryOperation(operation: String, left: T, right: T): T + + /** + * Curring version of [binaryOperation] + */ + public fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = { left, right -> + binaryOperation(operation, left, right) + } } /** @@ -45,11 +57,27 @@ public interface NumericAlgebra : Algebra { public fun leftSideNumberOperation(operation: String, left: Number, right: T): T = binaryOperation(operation, number(left), right) + /** + * Curring version of [leftSideNumberOperation] + */ + public fun leftSideNumberOperationFunction(operation: String): (left: Number, right: T) -> T = + { left: Number, right: T -> + leftSideNumberOperation(operation, left, right) + } + /** * Dynamic call of binary operation [operation] on [left] and [right] where right element is [Number]. */ public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = leftSideNumberOperation(operation, right, left) + + /** + * Curring version of [rightSideNumberOperation] + */ + public fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = + { left: T, right: Number -> + rightSideNumberOperation(operation, left, right) + } } /** diff --git a/settings.gradle.kts b/settings.gradle.kts index 10e4d9577..da33fea59 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,8 +8,8 @@ pluginManagement { maven("https://dl.bintray.com/kotlin/kotlinx") } - val toolsVersion = "0.7.0" - val kotlinVersion = "1.4.20" + val toolsVersion = "0.7.1" + val kotlinVersion = "1.4.21" plugins { id("kotlinx.benchmark") version "0.2.0-dev-20" From 484b35cb4fcb363053512baf3e619410d8ba03cc Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 18:34:35 +0700 Subject: [PATCH 12/55] Fix failing tests --- .../kmath/estree/internal/JSBuilder.kt | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt index b6b58179b..c77f0c9ef 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt @@ -56,18 +56,25 @@ internal class JSBuilder(val bodyCallback: JSBuilder.() -> BaseExpression) } } - fun variable(name: String): BaseExpression { - return MemberExpression( - computed = true, - optional = false, - `object` = Identifier("arguments"), - property = SimpleLiteral(name), - ) - } + fun variable(name: String): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name)) fun call(function: Function, vararg args: BaseExpression): BaseExpression = SimpleCallExpression( optional = false, callee = constant(function), *args, ) + + private companion object { + @Suppress("UNUSED_VARIABLE") + val getOrFail: (`object`: dynamic, key: String) -> dynamic = { `object`, key -> + val k = key + val o = `object` + + if (!(js("k in o") as Boolean)) { + throw NoSuchElementException() + } + + js("o[k]") + } + } } From 3cd00b9df60343767b81d5116196b441cbb5207a Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 18:55:59 +0700 Subject: [PATCH 13/55] Inline internal functions with one usage --- .../kscience/kmath/asm/internal/AsmBuilder.kt | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) 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 20e42ed25..882b95bf0 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 @@ -204,18 +204,13 @@ internal class AsmBuilder( */ fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex - loadThis() + invokeMethodVisitor.load(0, classType) getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) iconst(idx) visitInsn(AALOAD) if (type != OBJECT_TYPE) checkcast(type) } - /** - * Loads `this` variable. - */ - private fun loadThis(): Unit = invokeMethodVisitor.load(0, classType) - /** * Either loads a numeric constant [value] from the class's constants field or boxes a primitive * constant from the constant pool. @@ -234,27 +229,21 @@ internal class AsmBuilder( SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) } - box(primitive) + val r = PRIMITIVES_TO_BOXED.getValue(primitive) + + invokeMethodVisitor.invokestatic( + r.internalName, + "valueOf", + getMethodDescriptor(r, primitive), + false, + ) + return } loadObjectConstant(value, boxed) } - /** - * Boxes the current value and pushes it. - */ - private fun box(primitive: Type) { - val r = PRIMITIVES_TO_BOXED.getValue(primitive) - - invokeMethodVisitor.invokestatic( - r.internalName, - "valueOf", - getMethodDescriptor(r, primitive), - false, - ) - } - /** * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. */ From 95701bec1b36759242f2c05a06e8dc0ed01c0b8f Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 19:02:36 +0700 Subject: [PATCH 14/55] Add informative NoSuchElementException message --- .../kotlin/kscience/kmath/estree/internal/JSBuilder.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt index c77f0c9ef..c6a36b538 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt @@ -70,9 +70,8 @@ internal class JSBuilder(val bodyCallback: JSBuilder.() -> BaseExpression) val k = key val o = `object` - if (!(js("k in o") as Boolean)) { - throw NoSuchElementException() - } + if (!(js("k in o") as Boolean)) + throw NoSuchElementException("Key $key is missing in the map.") js("o[k]") } From 9a875bc7db3a3e1b5707c2cfdc4dfaec048bc1b2 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 19:04:09 +0700 Subject: [PATCH 15/55] Add missing newline --- kmath-ast/src/jsMain/kotlin/astring.global.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-ast/src/jsMain/kotlin/astring.global.kt b/kmath-ast/src/jsMain/kotlin/astring.global.kt index c69c26caf..d8514c310 100644 --- a/kmath-ast/src/jsMain/kotlin/astring.global.kt +++ b/kmath-ast/src/jsMain/kotlin/astring.global.kt @@ -14,4 +14,4 @@ external interface astring { var baseGenerator: Generator companion object : astring by definedExternally -} \ No newline at end of file +} From d9932042e84ccd1b36274619225fd9fcb5f390ff Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 19:04:43 +0700 Subject: [PATCH 16/55] Delete TS bindings --- kmath-ast/src/jsMain/kotlin/astring.d.ts | 50 -- kmath-ast/src/jsMain/kotlin/emitter.d.ts | 16 - kmath-ast/src/jsMain/kotlin/estree.d.ts | 569 ----------------------- kmath-ast/src/jsMain/kotlin/stream.d.ts | 5 - 4 files changed, 640 deletions(-) delete mode 100644 kmath-ast/src/jsMain/kotlin/astring.d.ts delete mode 100644 kmath-ast/src/jsMain/kotlin/emitter.d.ts delete mode 100644 kmath-ast/src/jsMain/kotlin/estree.d.ts delete mode 100644 kmath-ast/src/jsMain/kotlin/stream.d.ts diff --git a/kmath-ast/src/jsMain/kotlin/astring.d.ts b/kmath-ast/src/jsMain/kotlin/astring.d.ts deleted file mode 100644 index 22cd7e980..000000000 --- a/kmath-ast/src/jsMain/kotlin/astring.d.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Type definitions for astring 1.3 -// Project: https://github.com/davidbonnet/astring -// Definitions by: Nikolaj Kappler -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.8 - -import * as ESTree from 'estree'; -import 'node'; -import { Stream } from 'stream'; - -export interface Options { - /** string to use for indentation (defaults to " ") */ - indent?: string; - /** string to use for line endings (defaults to "\n") */ - lineEnd?: string; - /** indent level to start from (defaults to 0) */ - startingIndentLevel?: number; - /** generate comments if true (defaults to false) */ - comments?: boolean; - /** custom code generator (defaults to astring.baseGenerator) */ - generator?: object; - /** source map generator (defaults to null), see https://github.com/mozilla/source-map#sourcemapgenerator */ - sourceMap?: any; -} - -/** Returns a string representing the rendered code of the provided AST `node`. However, if an `output` stream is provided in the options, it writes to that stream and returns it. */ -export function generate(node: ESTree.Node, options?: Options): string; -/** Returns a string representing the rendered code of the provided AST `node`. However, if an `output` stream is provided in the options, it writes to that stream and returns it. */ -export function generate(node: ESTree.Node, options: Options & { - /** output stream to write the rendered code to (defaults to null) */ - output: Stream; -}): Stream; - -/** - * A code generator consists of a mapping of node names and functions that take two arguments: `node` and `state`. - * The `node` points to the node from which to generate the code and the `state` exposes the `write` method that takes generated code strings. - */ -export type Generator = { [key in ESTree.Node["type"]]: (node: Extract, state: { write(s: string): void }) => void }; - -/** Base generator that can be used to extend Astring. See https://github.com/davidbonnet/astring#extending */ -export const baseGenerator: Generator; - -declare global { - interface astring { - generate: typeof generate; - /** Base generator that can be used to extend Astring. See https://github.com/davidbonnet/astring#extending */ - baseGenerator: Generator; - } - const astring: astring; -} \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/emitter.d.ts b/kmath-ast/src/jsMain/kotlin/emitter.d.ts deleted file mode 100644 index 4970529d4..000000000 --- a/kmath-ast/src/jsMain/kotlin/emitter.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -export class Emitter { - constructor(obj: any) - constructor() - - on(event: string, fn: () => void) - - off(event: string, fn: () => void) - - once(event: string, fn: () => void) - - emit(event: string, ...any: any[]) - - listeners(event: string): (() => void)[] - - hasListeners(event: string): boolean -} diff --git a/kmath-ast/src/jsMain/kotlin/estree.d.ts b/kmath-ast/src/jsMain/kotlin/estree.d.ts deleted file mode 100644 index 927477c66..000000000 --- a/kmath-ast/src/jsMain/kotlin/estree.d.ts +++ /dev/null @@ -1,569 +0,0 @@ -// Type definitions for ESTree AST specification -// Project: https://github.com/estree/estree -// Definitions by: RReverser -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped - -// This definition file follows a somewhat unusual format. ESTree allows -// runtime type checks based on the `type` parameter. In order to explain this -// to typescript we want to use discriminated union types: -// https://github.com/Microsoft/TypeScript/pull/9163 -// -// For ESTree this is a bit tricky because the high level interfaces like -// Node or Function are pulling double duty. We want to pass common fields down -// to the interfaces that extend them (like Identifier or -// ArrowFunctionExpression), but you can't extend a type union or enforce -// common fields on them. So we've split the high level interfaces into two -// types, a base type which passes down inhereted fields, and a type union of -// all types which extend the base type. Only the type union is exported, and -// the union is how other types refer to the collection of inheriting types. -// -// This makes the definitions file here somewhat more difficult to maintain, -// but it has the notable advantage of making ESTree much easier to use as -// an end user. - -interface BaseNodeWithoutComments { - // Every leaf interface that extends BaseNode must specify a type property. - // The type property should be a string literal. For example, Identifier - // has: `type: "Identifier"` - type: string; - loc?: SourceLocation | null; - range?: [number, number]; -} - -interface BaseNode extends BaseNodeWithoutComments { - leadingComments?: Array; - trailingComments?: Array; -} - -export type Node = - Identifier | Literal | Program | Function | SwitchCase | CatchClause | - VariableDeclarator | Statement | Expression | Property | - AssignmentProperty | Super | TemplateElement | SpreadElement | Pattern | - ClassBody | Class | MethodDefinition | ModuleDeclaration | ModuleSpecifier; - -export interface Comment extends BaseNodeWithoutComments { - type: "Line" | "Block"; - value: string; -} - -interface SourceLocation { - source?: string | null; - start: Position; - end: Position; -} - -export interface Position { - /** >= 1 */ - line: number; - /** >= 0 */ - column: number; -} - -export interface Program extends BaseNode { - type: "Program"; - sourceType: "script" | "module"; - body: Array; - comments?: Array; -} - -export interface Directive extends BaseNode { - type: "ExpressionStatement"; - expression: Literal; - directive: string; -} - -interface BaseFunction extends BaseNode { - params: Array; - generator?: boolean; - async?: boolean; - // The body is either BlockStatement or Expression because arrow functions - // can have a body that's either. FunctionDeclarations and - // FunctionExpressions have only BlockStatement bodies. - body: BlockStatement | Expression; -} - -export type Function = - FunctionDeclaration | FunctionExpression | ArrowFunctionExpression; - -export type Statement = - ExpressionStatement | BlockStatement | EmptyStatement | - DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | - BreakStatement | ContinueStatement | IfStatement | SwitchStatement | - ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | - ForStatement | ForInStatement | ForOfStatement | Declaration; - -interface BaseStatement extends BaseNode { } - -export interface EmptyStatement extends BaseStatement { - type: "EmptyStatement"; -} - -export interface BlockStatement extends BaseStatement { - type: "BlockStatement"; - body: Array; - innerComments?: Array; -} - -export interface ExpressionStatement extends BaseStatement { - type: "ExpressionStatement"; - expression: Expression; -} - -export interface IfStatement extends BaseStatement { - type: "IfStatement"; - test: Expression; - consequent: Statement; - alternate?: Statement | null; -} - -export interface LabeledStatement extends BaseStatement { - type: "LabeledStatement"; - label: Identifier; - body: Statement; -} - -export interface BreakStatement extends BaseStatement { - type: "BreakStatement"; - label?: Identifier | null; -} - -export interface ContinueStatement extends BaseStatement { - type: "ContinueStatement"; - label?: Identifier | null; -} - -export interface WithStatement extends BaseStatement { - type: "WithStatement"; - object: Expression; - body: Statement; -} - -export interface SwitchStatement extends BaseStatement { - type: "SwitchStatement"; - discriminant: Expression; - cases: Array; -} - -export interface ReturnStatement extends BaseStatement { - type: "ReturnStatement"; - argument?: Expression | null; -} - -export interface ThrowStatement extends BaseStatement { - type: "ThrowStatement"; - argument: Expression; -} - -export interface TryStatement extends BaseStatement { - type: "TryStatement"; - block: BlockStatement; - handler?: CatchClause | null; - finalizer?: BlockStatement | null; -} - -export interface WhileStatement extends BaseStatement { - type: "WhileStatement"; - test: Expression; - body: Statement; -} - -export interface DoWhileStatement extends BaseStatement { - type: "DoWhileStatement"; - body: Statement; - test: Expression; -} - -export interface ForStatement extends BaseStatement { - type: "ForStatement"; - init?: VariableDeclaration | Expression | null; - test?: Expression | null; - update?: Expression | null; - body: Statement; -} - -interface BaseForXStatement extends BaseStatement { - left: VariableDeclaration | Pattern; - right: Expression; - body: Statement; -} - -export interface ForInStatement extends BaseForXStatement { - type: "ForInStatement"; -} - -export interface DebuggerStatement extends BaseStatement { - type: "DebuggerStatement"; -} - -export type Declaration = - FunctionDeclaration | VariableDeclaration | ClassDeclaration; - -interface BaseDeclaration extends BaseStatement { } - -export interface FunctionDeclaration extends BaseFunction, BaseDeclaration { - type: "FunctionDeclaration"; - /** It is null when a function declaration is a part of the `export default function` statement */ - id: Identifier | null; - body: BlockStatement; -} - -export interface VariableDeclaration extends BaseDeclaration { - type: "VariableDeclaration"; - declarations: Array; - kind: "var" | "let" | "const"; -} - -export interface VariableDeclarator extends BaseNode { - type: "VariableDeclarator"; - id: Pattern; - init?: Expression | null; -} - -type Expression = - ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | - ArrowFunctionExpression | YieldExpression | Literal | UnaryExpression | - UpdateExpression | BinaryExpression | AssignmentExpression | - LogicalExpression | MemberExpression | ConditionalExpression | - CallExpression | NewExpression | SequenceExpression | TemplateLiteral | - TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | - AwaitExpression | ImportExpression | ChainExpression; - -export interface BaseExpression extends BaseNode { } - -type ChainElement = SimpleCallExpression | MemberExpression; - -export interface ChainExpression extends BaseExpression { - type: "ChainExpression"; - expression: ChainElement; -} - -export interface ThisExpression extends BaseExpression { - type: "ThisExpression"; -} - -export interface ArrayExpression extends BaseExpression { - type: "ArrayExpression"; - elements: Array; -} - -export interface ObjectExpression extends BaseExpression { - type: "ObjectExpression"; - properties: Array; -} - -export interface Property extends BaseNode { - type: "Property"; - key: Expression; - value: Expression | Pattern; // Could be an AssignmentProperty - kind: "init" | "get" | "set"; - method: boolean; - shorthand: boolean; - computed: boolean; -} - -export interface FunctionExpression extends BaseFunction, BaseExpression { - id?: Identifier | null; - type: "FunctionExpression"; - body: BlockStatement; -} - -export interface SequenceExpression extends BaseExpression { - type: "SequenceExpression"; - expressions: Array; -} - -export interface UnaryExpression extends BaseExpression { - type: "UnaryExpression"; - operator: UnaryOperator; - prefix: true; - argument: Expression; -} - -export interface BinaryExpression extends BaseExpression { - type: "BinaryExpression"; - operator: BinaryOperator; - left: Expression; - right: Expression; -} - -export interface AssignmentExpression extends BaseExpression { - type: "AssignmentExpression"; - operator: AssignmentOperator; - left: Pattern | MemberExpression; - right: Expression; -} - -export interface UpdateExpression extends BaseExpression { - type: "UpdateExpression"; - operator: UpdateOperator; - argument: Expression; - prefix: boolean; -} - -export interface LogicalExpression extends BaseExpression { - type: "LogicalExpression"; - operator: LogicalOperator; - left: Expression; - right: Expression; -} - -export interface ConditionalExpression extends BaseExpression { - type: "ConditionalExpression"; - test: Expression; - alternate: Expression; - consequent: Expression; -} - -interface BaseCallExpression extends BaseExpression { - callee: Expression | Super; - arguments: Array; -} -export type CallExpression = SimpleCallExpression | NewExpression; - -export interface SimpleCallExpression extends BaseCallExpression { - type: "CallExpression"; - optional: boolean; -} - -export interface NewExpression extends BaseCallExpression { - type: "NewExpression"; -} - -export interface MemberExpression extends BaseExpression, BasePattern { - type: "MemberExpression"; - object: Expression | Super; - property: Expression; - computed: boolean; - optional: boolean; -} - -export type Pattern = - Identifier | ObjectPattern | ArrayPattern | RestElement | - AssignmentPattern | MemberExpression; - -interface BasePattern extends BaseNode { } - -export interface SwitchCase extends BaseNode { - type: "SwitchCase"; - test?: Expression | null; - consequent: Array; -} - -export interface CatchClause extends BaseNode { - type: "CatchClause"; - param: Pattern | null; - body: BlockStatement; -} - -export interface Identifier extends BaseNode, BaseExpression, BasePattern { - type: "Identifier"; - name: string; -} - -export type Literal = SimpleLiteral | RegExpLiteral; - -export interface SimpleLiteral extends BaseNode, BaseExpression { - type: "Literal"; - value: string | boolean | number | null; - raw?: string; -} - -export interface RegExpLiteral extends BaseNode, BaseExpression { - type: "Literal"; - value?: RegExp | null; - regex: { - pattern: string; - flags: string; - }; - raw?: string; -} - -export type UnaryOperator = - "-" | "+" | "!" | "~" | "typeof" | "void" | "delete"; - -export type BinaryOperator = - "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | - ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "**" | "|" | "^" | "&" | "in" | - "instanceof"; - -export type LogicalOperator = "||" | "&&" | "??"; - -export type AssignmentOperator = - "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "**=" | "<<=" | ">>=" | ">>>=" | - "|=" | "^=" | "&="; - -export type UpdateOperator = "++" | "--"; - -export interface ForOfStatement extends BaseForXStatement { - type: "ForOfStatement"; - await: boolean; -} - -export interface Super extends BaseNode { - type: "Super"; -} - -export interface SpreadElement extends BaseNode { - type: "SpreadElement"; - argument: Expression; -} - -export interface ArrowFunctionExpression extends BaseExpression, BaseFunction { - type: "ArrowFunctionExpression"; - expression: boolean; - body: BlockStatement | Expression; -} - -export interface YieldExpression extends BaseExpression { - type: "YieldExpression"; - argument?: Expression | null; - delegate: boolean; -} - -export interface TemplateLiteral extends BaseExpression { - type: "TemplateLiteral"; - quasis: Array; - expressions: Array; -} - -export interface TaggedTemplateExpression extends BaseExpression { - type: "TaggedTemplateExpression"; - tag: Expression; - quasi: TemplateLiteral; -} - -export interface TemplateElement extends BaseNode { - type: "TemplateElement"; - tail: boolean; - value: { - cooked: string; - raw: string; - }; -} - -export interface AssignmentProperty extends Property { - value: Pattern; - kind: "init"; - method: boolean; // false -} - -export interface ObjectPattern extends BasePattern { - type: "ObjectPattern"; - properties: Array; -} - -export interface ArrayPattern extends BasePattern { - type: "ArrayPattern"; - elements: Array; -} - -export interface RestElement extends BasePattern { - type: "RestElement"; - argument: Pattern; -} - -export interface AssignmentPattern extends BasePattern { - type: "AssignmentPattern"; - left: Pattern; - right: Expression; -} - -export type Class = ClassDeclaration | ClassExpression; -interface BaseClass extends BaseNode { - superClass?: Expression | null; - body: ClassBody; -} - -export interface ClassBody extends BaseNode { - type: "ClassBody"; - body: Array; -} - -export interface MethodDefinition extends BaseNode { - type: "MethodDefinition"; - key: Expression; - value: FunctionExpression; - kind: "constructor" | "method" | "get" | "set"; - computed: boolean; - static: boolean; -} - -export interface ClassDeclaration extends BaseClass, BaseDeclaration { - type: "ClassDeclaration"; - /** It is null when a class declaration is a part of the `export default class` statement */ - id: Identifier | null; -} - -export interface ClassExpression extends BaseClass, BaseExpression { - type: "ClassExpression"; - id?: Identifier | null; -} - -export interface MetaProperty extends BaseExpression { - type: "MetaProperty"; - meta: Identifier; - property: Identifier; -} - -export type ModuleDeclaration = - ImportDeclaration | ExportNamedDeclaration | ExportDefaultDeclaration | - ExportAllDeclaration; -interface BaseModuleDeclaration extends BaseNode { } - -export type ModuleSpecifier = - ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | - ExportSpecifier; -interface BaseModuleSpecifier extends BaseNode { - local: Identifier; -} - -export interface ImportDeclaration extends BaseModuleDeclaration { - type: "ImportDeclaration"; - specifiers: Array; - source: Literal; -} - -export interface ImportSpecifier extends BaseModuleSpecifier { - type: "ImportSpecifier"; - imported: Identifier; -} - -export interface ImportExpression extends BaseExpression { - type: "ImportExpression"; - source: Expression; -} - -export interface ImportDefaultSpecifier extends BaseModuleSpecifier { - type: "ImportDefaultSpecifier"; -} - -export interface ImportNamespaceSpecifier extends BaseModuleSpecifier { - type: "ImportNamespaceSpecifier"; -} - -export interface ExportNamedDeclaration extends BaseModuleDeclaration { - type: "ExportNamedDeclaration"; - declaration?: Declaration | null; - specifiers: Array; - source?: Literal | null; -} - -export interface ExportSpecifier extends BaseModuleSpecifier { - type: "ExportSpecifier"; - exported: Identifier; -} - -export interface ExportDefaultDeclaration extends BaseModuleDeclaration { - type: "ExportDefaultDeclaration"; - declaration: Declaration | Expression; -} - -export interface ExportAllDeclaration extends BaseModuleDeclaration { - type: "ExportAllDeclaration"; - source: Literal; -} - -export interface AwaitExpression extends BaseExpression { - type: "AwaitExpression"; - argument: Expression; -} \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/stream.d.ts b/kmath-ast/src/jsMain/kotlin/stream.d.ts deleted file mode 100644 index f98fcab8c..000000000 --- a/kmath-ast/src/jsMain/kotlin/stream.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {Emitter} from 'emitter' - -export class Stream extends Emitter { - pipe(dest: any, options: any): any -} From 4294bc1b97edbad2f7a6cfe3ea57409aa03bf611 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 19:23:10 +0700 Subject: [PATCH 17/55] Hide bindings from public API --- kmath-ast/src/jsMain/kotlin/astring.global.kt | 17 -- .../src/jsMain/kotlin/astring.typealises.kt | 3 - .../src/jsMain/kotlin/estree.extensions.kt | 67 ------- .../kmath/estree/internal/JSBuilder.kt | 17 +- .../kmath/estree/internal/astring}/astring.kt | 17 +- .../internal/astring/astring.typealises.kt | 3 + .../kmath/estree/internal/emitter}/emitter.kt | 14 +- .../internal/estree/estree.extensions.kt | 74 +++++++ .../kmath/estree/internal/estree}/estree.kt | 183 +++++++++--------- .../kmath/estree/internal/stream/stream.kt | 7 + .../internal/tsstdlib/lib.es2015.iterable.kt | 25 +++ .../estree/internal/tsstdlib}/lib.es5.kt | 22 +-- .../src/jsMain/kotlin/lib.es2015.iterable.kt | 28 --- kmath-ast/src/jsMain/kotlin/stream.kt | 13 -- 14 files changed, 230 insertions(+), 260 deletions(-) delete mode 100644 kmath-ast/src/jsMain/kotlin/astring.global.kt delete mode 100644 kmath-ast/src/jsMain/kotlin/astring.typealises.kt delete mode 100644 kmath-ast/src/jsMain/kotlin/estree.extensions.kt rename kmath-ast/src/jsMain/kotlin/{ => kscience/kmath/estree/internal/astring}/astring.kt (57%) create mode 100644 kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.typealises.kt rename kmath-ast/src/jsMain/kotlin/{ => kscience/kmath/estree/internal/emitter}/emitter.kt (51%) create mode 100644 kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt rename kmath-ast/src/jsMain/kotlin/{ => kscience/kmath/estree/internal/estree}/estree.kt (88%) create mode 100644 kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/stream/stream.kt create mode 100644 kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt rename kmath-ast/src/jsMain/kotlin/{ => kscience/kmath/estree/internal/tsstdlib}/lib.es5.kt (77%) delete mode 100644 kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt delete mode 100644 kmath-ast/src/jsMain/kotlin/stream.kt diff --git a/kmath-ast/src/jsMain/kotlin/astring.global.kt b/kmath-ast/src/jsMain/kotlin/astring.global.kt deleted file mode 100644 index d8514c310..000000000 --- a/kmath-ast/src/jsMain/kotlin/astring.global.kt +++ /dev/null @@ -1,17 +0,0 @@ -@file:JsQualifier("global") -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "PackageDirectoryMismatch", "ClassName" -) - -package global - -import Generator - -@Suppress("EXTERNAL_DELEGATION", "NESTED_CLASS_IN_EXTERNAL_INTERFACE") -external interface astring { - var generate: (dynamic, dynamic) -> dynamic - var baseGenerator: Generator - - companion object : astring by definedExternally -} diff --git a/kmath-ast/src/jsMain/kotlin/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/astring.typealises.kt deleted file mode 100644 index 9b74e2d04..000000000 --- a/kmath-ast/src/jsMain/kotlin/astring.typealises.kt +++ /dev/null @@ -1,3 +0,0 @@ -@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation") - -typealias Generator = Any diff --git a/kmath-ast/src/jsMain/kotlin/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/estree.extensions.kt deleted file mode 100644 index d4fc4baa1..000000000 --- a/kmath-ast/src/jsMain/kotlin/estree.extensions.kt +++ /dev/null @@ -1,67 +0,0 @@ -@file:Suppress( - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", - "NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING", "PackageDirectoryMismatch" -) - -package estree - -fun Program(sourceType: String, vararg body: dynamic) = object : Program { - override var type = "Program" - override var sourceType = sourceType - override var body = body -} - -fun VariableDeclaration(kind: String, vararg declarations: VariableDeclarator) = object : VariableDeclaration { - override var type = "VariableDeclaration" - override var declarations = declarations.toList().toTypedArray() - override var kind = kind -} - -fun VariableDeclarator(id: dynamic, init: dynamic) = object : VariableDeclarator { - override var type = "VariableDeclarator" - override var id = id - override var init = init -} - -fun Identifier(name: String) = object : Identifier { - override var type = "Identifier" - override var name = name -} - -fun FunctionExpression(params: Array, body: BlockStatement) = object : FunctionExpression { - override var params = params - override var type = "FunctionExpression" - override var body = body -} - -fun BlockStatement(vararg body: dynamic) = object : BlockStatement { - override var type = "BlockStatement" - override var body = body -} - -fun ReturnStatement(argument: dynamic) = object : ReturnStatement { - override var type = "ReturnStatement" - override var argument = argument -} - -fun SimpleLiteral(value: dynamic) = object : SimpleLiteral { - override var type = "Literal" - override var value = value -} - -fun MemberExpression(computed: Boolean, optional: Boolean, `object`: dynamic, property: dynamic) = - object : MemberExpression { - override var type = "MemberExpression" - override var computed = computed - override var optional = optional - override var `object` = `object` - override var property = property - } - -fun SimpleCallExpression(optional: Boolean, callee: dynamic, vararg arguments: dynamic) = - object : SimpleCallExpression { - override var type = "CallExpression" - override var optional = optional - override var callee = callee - override var arguments = arguments - } diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt index c6a36b538..b38be085d 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt @@ -1,18 +1,29 @@ package kscience.kmath.estree.internal -import astring.generate +import kscience.kmath.estree.internal.astring.generate import estree.* +import kscience.kmath.estree.internal.estree.* +import kscience.kmath.estree.internal.estree.BlockStatement +import kscience.kmath.estree.internal.estree.FunctionExpression +import kscience.kmath.estree.internal.estree.Identifier +import kscience.kmath.estree.internal.estree.MemberExpression +import kscience.kmath.estree.internal.estree.Program +import kscience.kmath.estree.internal.estree.ReturnStatement +import kscience.kmath.estree.internal.estree.SimpleCallExpression +import kscience.kmath.estree.internal.estree.SimpleLiteral +import kscience.kmath.estree.internal.estree.VariableDeclaration +import kscience.kmath.estree.internal.estree.VariableDeclarator import kscience.kmath.expressions.Expression import kscience.kmath.expressions.Symbol internal class JSBuilder(val bodyCallback: JSBuilder.() -> BaseExpression) { private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression { @Suppress("UNUSED_VARIABLE", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") - override fun invoke(map: Map): T { + override fun invoke(arguments: Map): T { val e = executable val c = constants val a = js("{}") - map.forEach { (key, value) -> a[key.identity] = value } + arguments.forEach { (key, value) -> a[key.identity] = value } return js("e(c, a)").unsafeCast() } } diff --git a/kmath-ast/src/jsMain/kotlin/astring.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt similarity index 57% rename from kmath-ast/src/jsMain/kotlin/astring.kt rename to kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt index fe2b2da0a..4ef3acf20 100644 --- a/kmath-ast/src/jsMain/kotlin/astring.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt @@ -1,16 +1,11 @@ -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "PackageDirectoryMismatch" -) - @file:JsModule("astring") @file:JsNonModule -package astring -import Generator +package kscience.kmath.estree.internal.astring + import estree.BaseNode -external interface Options { +internal external interface Options { var indent: String? get() = definedExternally set(value) = definedExternally @@ -31,8 +26,8 @@ external interface Options { set(value) = definedExternally } -external fun generate(node: BaseNode, options: Options /* Options & `T$0` */ = definedExternally): String +internal external fun generate(node: BaseNode, options: Options /* Options & `T$0` */ = definedExternally): String -external fun generate(node: BaseNode): String +internal external fun generate(node: BaseNode): String -external var baseGenerator: Generator +internal external var baseGenerator: Generator diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.typealises.kt new file mode 100644 index 000000000..5a7fe4f16 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.typealises.kt @@ -0,0 +1,3 @@ +package kscience.kmath.estree.internal.astring + +internal typealias Generator = Any diff --git a/kmath-ast/src/jsMain/kotlin/emitter.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/emitter/emitter.kt similarity index 51% rename from kmath-ast/src/jsMain/kotlin/emitter.kt rename to kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/emitter/emitter.kt index 94398397f..1e0a95a16 100644 --- a/kmath-ast/src/jsMain/kotlin/emitter.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/emitter/emitter.kt @@ -1,14 +1,6 @@ -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", - "OVERRIDING_FINAL_MEMBER", - "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "CONFLICTING_OVERLOADS", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "SortModifiers", - "PackageDirectoryMismatch" -) +package kscience.kmath.estree.internal.emitter -package emitter - -external open class Emitter { +internal open external class Emitter { constructor(obj: Any) constructor() @@ -18,4 +10,4 @@ external open class Emitter { open fun emit(event: String, vararg any: Any) open fun listeners(event: String): Array<() -> Unit> open fun hasListeners(event: String): Boolean -} \ No newline at end of file +} diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt new file mode 100644 index 000000000..951cd9ef8 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt @@ -0,0 +1,74 @@ +package kscience.kmath.estree.internal.estree + +import estree.* +import estree.BlockStatement +import estree.FunctionExpression +import estree.Identifier +import estree.MemberExpression +import estree.Program +import estree.ReturnStatement +import estree.SimpleCallExpression +import estree.SimpleLiteral +import estree.VariableDeclaration +import estree.VariableDeclarator + +internal fun Program(sourceType: String, vararg body: dynamic) = object : Program { + override var type = "Program" + override var sourceType = sourceType + override var body = body +} + +internal fun VariableDeclaration(kind: String, vararg declarations: VariableDeclarator) = object : VariableDeclaration { + override var type = "VariableDeclaration" + override var declarations = declarations.toList().toTypedArray() + override var kind = kind +} + +internal fun VariableDeclarator(id: dynamic, init: dynamic) = object : VariableDeclarator { + override var type = "VariableDeclarator" + override var id = id + override var init = init +} + +internal fun Identifier(name: String) = object : Identifier { + override var type = "Identifier" + override var name = name +} + +internal fun FunctionExpression(params: Array, body: BlockStatement) = object : FunctionExpression { + override var params = params + override var type = "FunctionExpression" + override var body = body +} + +internal fun BlockStatement(vararg body: dynamic) = object : BlockStatement { + override var type = "BlockStatement" + override var body = body +} + +internal fun ReturnStatement(argument: dynamic) = object : ReturnStatement { + override var type = "ReturnStatement" + override var argument = argument +} + +internal fun SimpleLiteral(value: dynamic) = object : SimpleLiteral { + override var type = "Literal" + override var value = value +} + +internal fun MemberExpression(computed: Boolean, optional: Boolean, `object`: dynamic, property: dynamic) = + object : MemberExpression { + override var type = "MemberExpression" + override var computed = computed + override var optional = optional + override var `object` = `object` + override var property = property + } + +internal fun SimpleCallExpression(optional: Boolean, callee: dynamic, vararg arguments: dynamic) = + object : SimpleCallExpression { + override var type = "CallExpression" + override var optional = optional + override var callee = callee + override var arguments = arguments + } diff --git a/kmath-ast/src/jsMain/kotlin/estree.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt similarity index 88% rename from kmath-ast/src/jsMain/kotlin/estree.kt rename to kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt index 79d043eae..8d894a1b1 100644 --- a/kmath-ast/src/jsMain/kotlin/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt @@ -1,13 +1,8 @@ -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "ClassName", "PackageDirectoryMismatch", -) - package estree import kotlin.js.RegExp -external interface BaseNodeWithoutComments { +internal external interface BaseNodeWithoutComments { var type: String var loc: SourceLocation? get() = definedExternally @@ -17,7 +12,7 @@ external interface BaseNodeWithoutComments { set(value) = definedExternally } -external interface BaseNode : BaseNodeWithoutComments { +internal external interface BaseNode : BaseNodeWithoutComments { var leadingComments: Array? get() = definedExternally set(value) = definedExternally @@ -26,12 +21,12 @@ external interface BaseNode : BaseNodeWithoutComments { set(value) = definedExternally } -external interface Comment : BaseNodeWithoutComments { +internal external interface Comment : BaseNodeWithoutComments { override var type: String /* "Line" | "Block" */ var value: String } -external interface SourceLocation { +internal external interface SourceLocation { var source: String? get() = definedExternally set(value) = definedExternally @@ -39,12 +34,12 @@ external interface SourceLocation { var end: Position } -external interface Position { +internal external interface Position { var line: Number var column: Number } -external interface Program : BaseNode { +internal external interface Program : BaseNode { override var type: String /* "Program" */ var sourceType: String /* "script" | "module" */ var body: Array @@ -53,7 +48,7 @@ external interface Program : BaseNode { set(value) = definedExternally } -external interface Directive : BaseNode { +internal external interface Directive : BaseNode { override var type: String /* "ExpressionStatement" */ var expression: dynamic /* SimpleLiteral | RegExpLiteral */ get() = definedExternally @@ -61,7 +56,7 @@ external interface Directive : BaseNode { var directive: String } -external interface BaseFunction : BaseNode { +internal external interface BaseFunction : BaseNode { var params: Array var generator: Boolean? get() = definedExternally @@ -74,13 +69,13 @@ external interface BaseFunction : BaseNode { set(value) = definedExternally } -external interface BaseStatement : BaseNode +internal external interface BaseStatement : BaseNode -external interface EmptyStatement : BaseStatement { +internal external interface EmptyStatement : BaseStatement { override var type: String /* "EmptyStatement" */ } -external interface BlockStatement : BaseStatement { +internal external interface BlockStatement : BaseStatement { override var type: String /* "BlockStatement" */ var body: Array var innerComments: Array? @@ -88,14 +83,14 @@ external interface BlockStatement : BaseStatement { set(value) = definedExternally } -external interface ExpressionStatement : BaseStatement { +internal external interface ExpressionStatement : BaseStatement { override var type: String /* "ExpressionStatement" */ var expression: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally set(value) = definedExternally } -external interface IfStatement : BaseStatement { +internal external interface IfStatement : BaseStatement { override var type: String /* "IfStatement" */ var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally @@ -108,7 +103,7 @@ external interface IfStatement : BaseStatement { set(value) = definedExternally } -external interface LabeledStatement : BaseStatement { +internal external interface LabeledStatement : BaseStatement { override var type: String /* "LabeledStatement" */ var label: Identifier var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ @@ -116,21 +111,21 @@ external interface LabeledStatement : BaseStatement { set(value) = definedExternally } -external interface BreakStatement : BaseStatement { +internal external interface BreakStatement : BaseStatement { override var type: String /* "BreakStatement" */ var label: Identifier? get() = definedExternally set(value) = definedExternally } -external interface ContinueStatement : BaseStatement { +internal external interface ContinueStatement : BaseStatement { override var type: String /* "ContinueStatement" */ var label: Identifier? get() = definedExternally set(value) = definedExternally } -external interface WithStatement : BaseStatement { +internal external interface WithStatement : BaseStatement { override var type: String /* "WithStatement" */ var `object`: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally @@ -140,7 +135,7 @@ external interface WithStatement : BaseStatement { set(value) = definedExternally } -external interface SwitchStatement : BaseStatement { +internal external interface SwitchStatement : BaseStatement { override var type: String /* "SwitchStatement" */ var discriminant: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally @@ -148,21 +143,21 @@ external interface SwitchStatement : BaseStatement { var cases: Array } -external interface ReturnStatement : BaseStatement { +internal external interface ReturnStatement : BaseStatement { override var type: String /* "ReturnStatement" */ var argument: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ get() = definedExternally set(value) = definedExternally } -external interface ThrowStatement : BaseStatement { +internal external interface ThrowStatement : BaseStatement { override var type: String /* "ThrowStatement" */ var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally set(value) = definedExternally } -external interface TryStatement : BaseStatement { +internal external interface TryStatement : BaseStatement { override var type: String /* "TryStatement" */ var block: BlockStatement var handler: CatchClause? @@ -173,7 +168,7 @@ external interface TryStatement : BaseStatement { set(value) = definedExternally } -external interface WhileStatement : BaseStatement { +internal external interface WhileStatement : BaseStatement { override var type: String /* "WhileStatement" */ var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally @@ -183,7 +178,7 @@ external interface WhileStatement : BaseStatement { set(value) = definedExternally } -external interface DoWhileStatement : BaseStatement { +internal external interface DoWhileStatement : BaseStatement { override var type: String /* "DoWhileStatement" */ var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ get() = definedExternally @@ -193,7 +188,7 @@ external interface DoWhileStatement : BaseStatement { set(value) = definedExternally } -external interface ForStatement : BaseStatement { +internal external interface ForStatement : BaseStatement { override var type: String /* "ForStatement" */ var init: dynamic /* VariableDeclaration? | ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ get() = definedExternally @@ -209,7 +204,7 @@ external interface ForStatement : BaseStatement { set(value) = definedExternally } -external interface BaseForXStatement : BaseStatement { +internal external interface BaseForXStatement : BaseStatement { var left: dynamic /* VariableDeclaration | Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ get() = definedExternally set(value) = definedExternally @@ -221,29 +216,29 @@ external interface BaseForXStatement : BaseStatement { set(value) = definedExternally } -external interface ForInStatement : BaseForXStatement { +internal external interface ForInStatement : BaseForXStatement { override var type: String /* "ForInStatement" */ } -external interface DebuggerStatement : BaseStatement { +internal external interface DebuggerStatement : BaseStatement { override var type: String /* "DebuggerStatement" */ } -external interface BaseDeclaration : BaseStatement +internal external interface BaseDeclaration : BaseStatement -external interface FunctionDeclaration : BaseFunction, BaseDeclaration { +internal external interface FunctionDeclaration : BaseFunction, BaseDeclaration { override var type: String /* "FunctionDeclaration" */ var id: Identifier? override var body: BlockStatement } -external interface VariableDeclaration : BaseDeclaration { +internal external interface VariableDeclaration : BaseDeclaration { override var type: String /* "VariableDeclaration" */ var declarations: Array var kind: String /* "var" | "let" | "const" */ } -external interface VariableDeclarator : BaseNode { +internal external interface VariableDeclarator : BaseNode { override var type: String /* "VariableDeclarator" */ var id: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ get() = definedExternally @@ -253,30 +248,30 @@ external interface VariableDeclarator : BaseNode { set(value) = definedExternally } -external interface BaseExpression : BaseNode +internal external interface BaseExpression : BaseNode -external interface ChainExpression : BaseExpression { +internal external interface ChainExpression : BaseExpression { override var type: String /* "ChainExpression" */ var expression: dynamic /* SimpleCallExpression | MemberExpression */ get() = definedExternally set(value) = definedExternally } -external interface ThisExpression : BaseExpression { +internal external interface ThisExpression : BaseExpression { override var type: String /* "ThisExpression" */ } -external interface ArrayExpression : BaseExpression { +internal external interface ArrayExpression : BaseExpression { override var type: String /* "ArrayExpression" */ var elements: Array } -external interface ObjectExpression : BaseExpression { +internal external interface ObjectExpression : BaseExpression { override var type: String /* "ObjectExpression" */ var properties: Array } -external interface Property : BaseNode { +internal external interface Property : BaseNode { override var type: String /* "Property" */ var key: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally @@ -290,7 +285,7 @@ external interface Property : BaseNode { var computed: Boolean } -external interface FunctionExpression : BaseFunction, BaseExpression { +internal external interface FunctionExpression : BaseFunction, BaseExpression { var id: Identifier? get() = definedExternally set(value) = definedExternally @@ -298,12 +293,12 @@ external interface FunctionExpression : BaseFunction, BaseExpression { override var body: BlockStatement } -external interface SequenceExpression : BaseExpression { +internal external interface SequenceExpression : BaseExpression { override var type: String /* "SequenceExpression" */ var expressions: Array } -external interface UnaryExpression : BaseExpression { +internal external interface UnaryExpression : BaseExpression { override var type: String /* "UnaryExpression" */ var operator: String /* "-" | "+" | "!" | "~" | "typeof" | "void" | "delete" */ var prefix: Boolean @@ -312,7 +307,7 @@ external interface UnaryExpression : BaseExpression { set(value) = definedExternally } -external interface BinaryExpression : BaseExpression { +internal external interface BinaryExpression : BaseExpression { override var type: String /* "BinaryExpression" */ var operator: String /* "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "**" | "|" | "^" | "&" | "in" | "instanceof" */ var left: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ @@ -323,7 +318,7 @@ external interface BinaryExpression : BaseExpression { set(value) = definedExternally } -external interface AssignmentExpression : BaseExpression { +internal external interface AssignmentExpression : BaseExpression { override var type: String /* "AssignmentExpression" */ var operator: String /* "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "**=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=" */ var left: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ @@ -334,7 +329,7 @@ external interface AssignmentExpression : BaseExpression { set(value) = definedExternally } -external interface UpdateExpression : BaseExpression { +internal external interface UpdateExpression : BaseExpression { override var type: String /* "UpdateExpression" */ var operator: String /* "++" | "--" */ var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ @@ -343,7 +338,7 @@ external interface UpdateExpression : BaseExpression { var prefix: Boolean } -external interface LogicalExpression : BaseExpression { +internal external interface LogicalExpression : BaseExpression { override var type: String /* "LogicalExpression" */ var operator: String /* "||" | "&&" | "??" */ var left: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ @@ -354,7 +349,7 @@ external interface LogicalExpression : BaseExpression { set(value) = definedExternally } -external interface ConditionalExpression : BaseExpression { +internal external interface ConditionalExpression : BaseExpression { override var type: String /* "ConditionalExpression" */ var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally @@ -367,23 +362,23 @@ external interface ConditionalExpression : BaseExpression { set(value) = definedExternally } -external interface BaseCallExpression : BaseExpression { +internal external interface BaseCallExpression : BaseExpression { var callee: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | Super */ get() = definedExternally set(value) = definedExternally var arguments: Array } -external interface SimpleCallExpression : BaseCallExpression { +internal external interface SimpleCallExpression : BaseCallExpression { override var type: String /* "CallExpression" */ var optional: Boolean } -external interface NewExpression : BaseCallExpression { +internal external interface NewExpression : BaseCallExpression { override var type: String /* "NewExpression" */ } -external interface MemberExpression : BaseExpression, BasePattern { +internal external interface MemberExpression : BaseExpression, BasePattern { override var type: String /* "MemberExpression" */ var `object`: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | Super */ get() = definedExternally @@ -395,9 +390,9 @@ external interface MemberExpression : BaseExpression, BasePattern { var optional: Boolean } -external interface BasePattern : BaseNode +internal external interface BasePattern : BaseNode -external interface SwitchCase : BaseNode { +internal external interface SwitchCase : BaseNode { override var type: String /* "SwitchCase" */ var test: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ get() = definedExternally @@ -405,7 +400,7 @@ external interface SwitchCase : BaseNode { var consequent: Array } -external interface CatchClause : BaseNode { +internal external interface CatchClause : BaseNode { override var type: String /* "CatchClause" */ var param: dynamic /* Identifier? | ObjectPattern? | ArrayPattern? | RestElement? | AssignmentPattern? | MemberExpression? */ get() = definedExternally @@ -413,12 +408,12 @@ external interface CatchClause : BaseNode { var body: BlockStatement } -external interface Identifier : BaseNode, BaseExpression, BasePattern { +internal external interface Identifier : BaseNode, BaseExpression, BasePattern { override var type: String /* "Identifier" */ var name: String } -external interface SimpleLiteral : BaseNode, BaseExpression { +internal external interface SimpleLiteral : BaseNode, BaseExpression { override var type: String /* "Literal" */ var value: dynamic /* String? | Boolean? | Number? */ get() = definedExternally @@ -428,12 +423,12 @@ external interface SimpleLiteral : BaseNode, BaseExpression { set(value) = definedExternally } -external interface `T$1` { +internal external interface `T$1` { var pattern: String var flags: String } -external interface RegExpLiteral : BaseNode, BaseExpression { +internal external interface RegExpLiteral : BaseNode, BaseExpression { override var type: String /* "Literal" */ var value: RegExp? get() = definedExternally @@ -444,23 +439,23 @@ external interface RegExpLiteral : BaseNode, BaseExpression { set(value) = definedExternally } -external interface ForOfStatement : BaseForXStatement { +internal external interface ForOfStatement : BaseForXStatement { override var type: String /* "ForOfStatement" */ var await: Boolean } -external interface Super : BaseNode { +internal external interface Super : BaseNode { override var type: String /* "Super" */ } -external interface SpreadElement : BaseNode { +internal external interface SpreadElement : BaseNode { override var type: String /* "SpreadElement" */ var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally set(value) = definedExternally } -external interface ArrowFunctionExpression : BaseExpression, BaseFunction { +internal external interface ArrowFunctionExpression : BaseExpression, BaseFunction { override var type: String /* "ArrowFunctionExpression" */ var expression: Boolean override var body: dynamic /* BlockStatement | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ @@ -468,7 +463,7 @@ external interface ArrowFunctionExpression : BaseExpression, BaseFunction { set(value) = definedExternally } -external interface YieldExpression : BaseExpression { +internal external interface YieldExpression : BaseExpression { override var type: String /* "YieldExpression" */ var argument: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ get() = definedExternally @@ -476,13 +471,13 @@ external interface YieldExpression : BaseExpression { var delegate: Boolean } -external interface TemplateLiteral : BaseExpression { +internal external interface TemplateLiteral : BaseExpression { override var type: String /* "TemplateLiteral" */ var quasis: Array var expressions: Array } -external interface TaggedTemplateExpression : BaseExpression { +internal external interface TaggedTemplateExpression : BaseExpression { override var type: String /* "TaggedTemplateExpression" */ var tag: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally @@ -490,18 +485,18 @@ external interface TaggedTemplateExpression : BaseExpression { var quasi: TemplateLiteral } -external interface `T$2` { +internal external interface `T$2` { var cooked: String var raw: String } -external interface TemplateElement : BaseNode { +internal external interface TemplateElement : BaseNode { override var type: String /* "TemplateElement" */ var tail: Boolean var value: `T$2` } -external interface AssignmentProperty : Property { +internal external interface AssignmentProperty : Property { override var value: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ get() = definedExternally set(value) = definedExternally @@ -509,24 +504,24 @@ external interface AssignmentProperty : Property { override var method: Boolean } -external interface ObjectPattern : BasePattern { +internal external interface ObjectPattern : BasePattern { override var type: String /* "ObjectPattern" */ var properties: Array } -external interface ArrayPattern : BasePattern { +internal external interface ArrayPattern : BasePattern { override var type: String /* "ArrayPattern" */ var elements: Array } -external interface RestElement : BasePattern { +internal external interface RestElement : BasePattern { override var type: String /* "RestElement" */ var argument: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ get() = definedExternally set(value) = definedExternally } -external interface AssignmentPattern : BasePattern { +internal external interface AssignmentPattern : BasePattern { override var type: String /* "AssignmentPattern" */ var left: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ get() = definedExternally @@ -536,19 +531,19 @@ external interface AssignmentPattern : BasePattern { set(value) = definedExternally } -external interface BaseClass : BaseNode { +internal external interface BaseClass : BaseNode { var superClass: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ get() = definedExternally set(value) = definedExternally var body: ClassBody } -external interface ClassBody : BaseNode { +internal external interface ClassBody : BaseNode { override var type: String /* "ClassBody" */ var body: Array } -external interface MethodDefinition : BaseNode { +internal external interface MethodDefinition : BaseNode { override var type: String /* "MethodDefinition" */ var key: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally @@ -559,31 +554,31 @@ external interface MethodDefinition : BaseNode { var static: Boolean } -external interface ClassDeclaration : BaseClass, BaseDeclaration { +internal external interface ClassDeclaration : BaseClass, BaseDeclaration { override var type: String /* "ClassDeclaration" */ var id: Identifier? } -external interface ClassExpression : BaseClass, BaseExpression { +internal external interface ClassExpression : BaseClass, BaseExpression { override var type: String /* "ClassExpression" */ var id: Identifier? get() = definedExternally set(value) = definedExternally } -external interface MetaProperty : BaseExpression { +internal external interface MetaProperty : BaseExpression { override var type: String /* "MetaProperty" */ var meta: Identifier var property: Identifier } -external interface BaseModuleDeclaration : BaseNode +internal external interface BaseModuleDeclaration : BaseNode -external interface BaseModuleSpecifier : BaseNode { +internal external interface BaseModuleSpecifier : BaseNode { var local: Identifier } -external interface ImportDeclaration : BaseModuleDeclaration { +internal external interface ImportDeclaration : BaseModuleDeclaration { override var type: String /* "ImportDeclaration" */ var specifiers: Array var source: dynamic /* SimpleLiteral | RegExpLiteral */ @@ -591,27 +586,27 @@ external interface ImportDeclaration : BaseModuleDeclaration { set(value) = definedExternally } -external interface ImportSpecifier : BaseModuleSpecifier { +internal external interface ImportSpecifier : BaseModuleSpecifier { override var type: String /* "ImportSpecifier" */ var imported: Identifier } -external interface ImportExpression : BaseExpression { +internal external interface ImportExpression : BaseExpression { override var type: String /* "ImportExpression" */ var source: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally set(value) = definedExternally } -external interface ImportDefaultSpecifier : BaseModuleSpecifier { +internal external interface ImportDefaultSpecifier : BaseModuleSpecifier { override var type: String /* "ImportDefaultSpecifier" */ } -external interface ImportNamespaceSpecifier : BaseModuleSpecifier { +internal external interface ImportNamespaceSpecifier : BaseModuleSpecifier { override var type: String /* "ImportNamespaceSpecifier" */ } -external interface ExportNamedDeclaration : BaseModuleDeclaration { +internal external interface ExportNamedDeclaration : BaseModuleDeclaration { override var type: String /* "ExportNamedDeclaration" */ var declaration: dynamic /* FunctionDeclaration? | VariableDeclaration? | ClassDeclaration? */ get() = definedExternally @@ -622,28 +617,28 @@ external interface ExportNamedDeclaration : BaseModuleDeclaration { set(value) = definedExternally } -external interface ExportSpecifier : BaseModuleSpecifier { +internal external interface ExportSpecifier : BaseModuleSpecifier { override var type: String /* "ExportSpecifier" */ var exported: Identifier } -external interface ExportDefaultDeclaration : BaseModuleDeclaration { +internal external interface ExportDefaultDeclaration : BaseModuleDeclaration { override var type: String /* "ExportDefaultDeclaration" */ var declaration: dynamic /* FunctionDeclaration | VariableDeclaration | ClassDeclaration | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally set(value) = definedExternally } -external interface ExportAllDeclaration : BaseModuleDeclaration { +internal external interface ExportAllDeclaration : BaseModuleDeclaration { override var type: String /* "ExportAllDeclaration" */ var source: dynamic /* SimpleLiteral | RegExpLiteral */ get() = definedExternally set(value) = definedExternally } -external interface AwaitExpression : BaseExpression { +internal external interface AwaitExpression : BaseExpression { override var type: String /* "AwaitExpression" */ var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ get() = definedExternally set(value) = definedExternally -} \ No newline at end of file +} diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/stream/stream.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/stream/stream.kt new file mode 100644 index 000000000..b3c65a758 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/stream/stream.kt @@ -0,0 +1,7 @@ +package kscience.kmath.estree.internal.stream + +import kscience.kmath.estree.internal.emitter.Emitter + +internal open external class Stream : Emitter { + open fun pipe(dest: Any, options: Any): Any +} diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt new file mode 100644 index 000000000..22d4dd8e0 --- /dev/null +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt @@ -0,0 +1,25 @@ +package kscience.kmath.estree.internal.tsstdlib + +internal external interface IteratorYieldResult { + var done: Boolean? + get() = definedExternally + set(value) = definedExternally + var value: TYield +} + +internal external interface IteratorReturnResult { + var done: Boolean + var value: TReturn +} + +internal external interface Iterator { + fun next(vararg args: Any /* JsTuple<> | JsTuple */): dynamic /* IteratorYieldResult | IteratorReturnResult */ + val `return`: ((value: TReturn) -> dynamic)? + val `throw`: ((e: Any) -> dynamic)? +} + +internal typealias Iterator__1 = Iterator + +internal external interface Iterable + +internal external interface IterableIterator : Iterator__1 diff --git a/kmath-ast/src/jsMain/kotlin/lib.es5.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es5.kt similarity index 77% rename from kmath-ast/src/jsMain/kotlin/lib.es5.kt rename to kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es5.kt index fe3847232..70f6d9702 100644 --- a/kmath-ast/src/jsMain/kotlin/lib.es5.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es5.kt @@ -1,18 +1,14 @@ -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "DEPRECATION", "PackageDirectoryMismatch", "KDocMissingDocumentation", - "PropertyName" -) +@file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION") -package tsstdlib +package kscience.kmath.estree.internal.tsstdlib import kotlin.js.RegExp -typealias RegExpMatchArray = Array +internal typealias RegExpMatchArray = Array -typealias RegExpExecArray = Array +internal typealias RegExpExecArray = Array -external interface RegExpConstructor { +internal external interface RegExpConstructor { @nativeInvoke operator fun invoke(pattern: RegExp, flags: String = definedExternally): RegExp @@ -37,7 +33,7 @@ external interface RegExpConstructor { var lastMatch: String } -external interface ConcatArray { +internal external interface ConcatArray { var length: Number @nativeGetter @@ -49,7 +45,7 @@ external interface ConcatArray { fun slice(start: Number = definedExternally, end: Number = definedExternally): Array } -external interface ArrayConstructor { +internal external interface ArrayConstructor { fun from(iterable: Iterable): Array fun from(iterable: ArrayLike): Array fun from(iterable: Iterable, mapfn: (v: T, k: Number) -> U, thisArg: Any = definedExternally): Array @@ -73,7 +69,7 @@ external interface ArrayConstructor { var prototype: Array } -external interface ArrayLike { +internal external interface ArrayLike { var length: Number @nativeGetter @@ -83,4 +79,4 @@ external interface ArrayLike { operator fun set(n: Number, value: T) } -typealias Extract = Any \ No newline at end of file +internal typealias Extract = Any diff --git a/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt deleted file mode 100644 index b55785a8e..000000000 --- a/kmath-ast/src/jsMain/kotlin/lib.es2015.iterable.kt +++ /dev/null @@ -1,28 +0,0 @@ -@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation", "PackageDirectoryMismatch" -) -package tsstdlib - -external interface IteratorYieldResult { - var done: Boolean? - get() = definedExternally - set(value) = definedExternally - var value: TYield -} - -external interface IteratorReturnResult { - var done: Boolean - var value: TReturn -} - -external interface Iterator { - fun next(vararg args: Any /* JsTuple<> | JsTuple */): dynamic /* IteratorYieldResult | IteratorReturnResult */ - val `return`: ((value: TReturn) -> dynamic)? - val `throw`: ((e: Any) -> dynamic)? -} - -typealias Iterator__1 = Iterator - -external interface Iterable - -external interface IterableIterator : Iterator__1 \ No newline at end of file diff --git a/kmath-ast/src/jsMain/kotlin/stream.kt b/kmath-ast/src/jsMain/kotlin/stream.kt deleted file mode 100644 index c6c30446c..000000000 --- a/kmath-ast/src/jsMain/kotlin/stream.kt +++ /dev/null @@ -1,13 +0,0 @@ -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "SortModifiers", - "KDocMissingDocumentation", "PackageDirectoryMismatch" -) - -package stream - -import emitter.Emitter - -external open class Stream : Emitter { - open fun pipe(dest: Any, options: Any): Any -} \ No newline at end of file From d70b185b3ea80f4686e860f6edf9d8bc0c334652 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 20:41:17 +0700 Subject: [PATCH 18/55] Update documentation for Algebra, add overloads for xOperation that invokes an operation not dispatches it --- .../kscience/kmath/operations/Algebra.kt | 153 +++++++++++++++--- 1 file changed, 132 insertions(+), 21 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index 2661525fb..3dfd14921 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -13,21 +13,79 @@ public annotation class KMathContext */ public interface Algebra { /** - * Wraps raw string or variable. + * Wraps a raw string to [T] object. This method is designed for three purposes: + * + * 1. Mathematical constants (`e`, `pi`). + * 2. Variables for expression-like contexts (`a`, `b`, `c`...). + * 3. Literals (`{1, 2}`, (`(3; 4)`)). + * + * In case if algebra can't parse the string, this method must throw [kotlin.IllegalStateException]. + * + * @param value the raw string. + * @return an object. */ public fun symbol(value: String): T = error("Wrapping of '$value' is not supported in $this") /** - * Dynamically dispatches an unary operation with name [operation]. + * Dynamically dispatches an unary operation with the certain name. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second `unaryOperation` overload: + * i.e. `unaryOperation(a)(b) == unaryOperation(a, b)`. + * + * @param operation the name of operation. + * @return an operation. */ public fun unaryOperation(operation: String): (arg: T) -> T = error("Unary operation $operation not defined in $this") /** - * Dynamically dispatches a binary operation with name [operation]. + * Dynamically invokes an unary operation with the certain name. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second [unaryOperation] overload: + * i.e. `unaryOperation(a)(b) == unaryOperation(a, b)`. + * + * @param operation the name of operation. + * @param arg the argument of operation. + * @return a result of operation. + */ + public fun unaryOperation(operation: String, arg: T): T = unaryOperation(operation)(arg) + + /** + * Dynamically dispatches a binary operation with the certain name. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second [binaryOperation] overload: + * i.e. `binaryOperation(a)(b, c) == binaryOperation(a, b, c)`. + * + * @param operation the name of operation. + * @return an operation. */ public fun binaryOperation(operation: String): (left: T, right: T) -> T = error("Binary operation $operation not defined in $this") + + /** + * Dynamically invokes a binary operation with the certain name. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second [binaryOperation] overload: + * i.e. `binaryOperation(a)(b, c) == binaryOperation(a, b, c)`. + * + * @param operation the name of operation. + * @param left the first argument of operation. + * @param right the second argument of operation. + * @return a result of operation. + */ + public fun binaryOperation(operation: String, left: T, right: T): T = binaryOperation(operation)(left, right) } /** @@ -37,33 +95,76 @@ public interface Algebra { */ public interface NumericAlgebra : Algebra { /** - * Wraps a number. + * Wraps a number to [T] object. + * + * @param value the number to wrap. + * @return an object. */ public fun number(value: Number): T /** - * Dynamically dispatches a binary operation with name [operation] where the left argument is [Number]. + * Dynamically dispatches a binary operation with the certain name with numeric first argument. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with the other [leftSideNumberOperation] overload: + * i.e. `leftSideNumberOperation(a)(b, c) == leftSideNumberOperation(a, b)`. + * + * @param operation the name of operation. + * @return an operation. */ public fun leftSideNumberOperation(operation: String): (left: Number, right: T) -> T = { l, r -> binaryOperation(operation)(number(l), r) } -// /** -// * Dynamically calls a binary operation with name [operation] where the left argument is [Number]. -// */ -// public fun leftSideNumberOperation(operation: String, left: Number, right: T): T = -// leftSideNumberOperation(operation)(left, right) + /** + * Dynamically invokes a binary operation with the certain name with numeric first argument. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second [leftSideNumberOperation] overload: + * i.e. `leftSideNumberOperation(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * + * @param operation the name of operation. + * @param left the first argument of operation. + * @param right the second argument of operation. + * @return a result of operation. + */ + public fun leftSideNumberOperation(operation: String, left: Number, right: T): T = + leftSideNumberOperation(operation)(left, right) /** - * Dynamically dispatches a binary operation with name [operation] where the right argument is [Number]. + * Dynamically dispatches a binary operation with the certain name with numeric first argument. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with the other [rightSideNumberOperation] overload: + * i.e. `rightSideNumberOperation(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * + * @param operation the name of operation. + * @return an operation. */ public fun rightSideNumberOperation(operation: String): (left: T, right: Number) -> T = { l, r -> binaryOperation(operation)(l, number(r)) } -// /** -// * Dynamically calls a binary operation with name [operation] where the right argument is [Number]. -// */ -// public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = -// rightSideNumberOperation(operation)(left, right) + /** + * Dynamically invokes a binary operation with the certain name with numeric second argument. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with the other [rightSideNumberOperation] overload: + * i.e. `rightSideNumberOperation(a)(b, c) == rightSideNumberOperation(a, b, c)`. + * + * @param operation the name of operation. + * @param left the first argument of operation. + * @param right the second argument of operation. + * @return a result of operation. + */ + public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = + rightSideNumberOperation(operation)(left, right) } /** @@ -160,13 +261,13 @@ public interface SpaceOperations : Algebra { */ public operator fun Number.times(b: T): T = b * this - override fun unaryOperation(operation: String): (arg: T) -> T = when (operation) { + public override fun unaryOperation(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> arg } MINUS_OPERATION -> { arg -> -arg } else -> super.unaryOperation(operation) } - override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { + public override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { PLUS_OPERATION -> ::add MINUS_OPERATION -> { left, right -> left - right } else -> super.binaryOperation(operation) @@ -196,6 +297,11 @@ public interface Space : SpaceOperations { * The neutral element of addition. */ public val zero: T + + public override fun symbol(value: String): T = when (value) { + "zero" -> zero + else -> super.symbol(value) + } } /** @@ -221,7 +327,7 @@ public interface RingOperations : SpaceOperations { */ public operator fun T.times(b: T): T = multiply(this, b) - override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { + public override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { TIMES_OPERATION -> ::multiply else -> super.binaryOperation(operation) } @@ -246,7 +352,12 @@ public interface Ring : Space, RingOperations, NumericAlgebra { */ public val one: T - override fun number(value: Number): T = one * value.toDouble() + public override fun number(value: Number): T = one * value.toDouble() + + public override fun symbol(value: String): T = when (value) { + "one" -> one + else -> super.symbol(value) + } /** * Addition of element and scalar. @@ -308,7 +419,7 @@ public interface FieldOperations : RingOperations { */ public operator fun T.div(b: T): T = divide(this, b) - override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { + public override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { DIV_OPERATION -> ::divide else -> super.binaryOperation(operation) } From 9fbca45235ba88186170a2f909c456abac5ef71e Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 20:48:38 +0700 Subject: [PATCH 19/55] Fix incorrect properties in verifier classes --- .../kotlin/kscience/kmath/operations/internal/FieldVerifier.kt | 2 ++ .../kotlin/kscience/kmath/operations/internal/RingVerifier.kt | 2 +- .../kotlin/kscience/kmath/operations/internal/SpaceVerifier.kt | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/FieldVerifier.kt b/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/FieldVerifier.kt index 1ca09ab0c..89f31c75b 100644 --- a/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/FieldVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/FieldVerifier.kt @@ -12,6 +12,8 @@ internal class FieldVerifier(override val algebra: Field, a: T, b: T, c: T super.verify() algebra { + assertEquals(a + b, b + a, "Addition in $algebra is not commutative.") + assertEquals(a * b, b * a, "Multiplication in $algebra is not commutative.") assertNotEquals(a / b, b / a, "Division in $algebra is not anti-commutative.") assertNotEquals((a / b) / c, a / (b / c), "Division in $algebra is associative.") assertEquals((a + b) / c, (a / c) + (b / c), "Division in $algebra is not right-distributive.") diff --git a/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/RingVerifier.kt b/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/RingVerifier.kt index 863169b9b..359ba1701 100644 --- a/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/RingVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/RingVerifier.kt @@ -10,7 +10,7 @@ internal open class RingVerifier(override val algebra: Ring, a: T, b: T, c super.verify() algebra { - assertEquals(a * b, a * b, "Multiplication in $algebra is not commutative.") + assertEquals(a + b, b + a, "Addition in $algebra is not commutative.") assertEquals(a * b * c, a * (b * c), "Multiplication in $algebra is not associative.") assertEquals(c * (a + b), (c * a) + (c * b), "Multiplication in $algebra is not distributive.") assertEquals(a * one, one * a, "$one in $algebra is not a neutral multiplication element.") diff --git a/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/SpaceVerifier.kt b/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/SpaceVerifier.kt index 4dc855829..045abb71f 100644 --- a/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/SpaceVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/kscience/kmath/operations/internal/SpaceVerifier.kt @@ -15,7 +15,6 @@ internal open class SpaceVerifier( AlgebraicVerifier> { override fun verify() { algebra { - assertEquals(a + b, b + a, "Addition in $algebra is not commutative.") assertEquals(a + b + c, a + (b + c), "Addition in $algebra is not associative.") assertEquals(x * (a + b), x * a + x * b, "Addition in $algebra is not distributive.") assertEquals((a + b) * x, a * x + b * x, "Addition in $algebra is not distributive.") From c8df741a4e2c7d45f25d4ce8c083250a524f514a Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 20:58:52 +0700 Subject: [PATCH 20/55] Remove incorrent symbol decl. --- .../kotlin/kscience/kmath/operations/Algebra.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index 3dfd14921..6cf9eeb78 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -297,11 +297,6 @@ public interface Space : SpaceOperations { * The neutral element of addition. */ public val zero: T - - public override fun symbol(value: String): T = when (value) { - "zero" -> zero - else -> super.symbol(value) - } } /** @@ -354,11 +349,6 @@ public interface Ring : Space, RingOperations, NumericAlgebra { public override fun number(value: Number): T = one * value.toDouble() - public override fun symbol(value: String): T = when (value) { - "one" -> one - else -> super.symbol(value) - } - /** * Addition of element and scalar. * From 69b1952c15150b0a4a39330ed82be52b93671d38 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 21:13:11 +0700 Subject: [PATCH 21/55] Add verification of NDField --- .../kotlin/kscience/kmath/structures/NDFieldTest.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NDFieldTest.kt index 79b56ea4a..b763ec7de 100644 --- a/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NDFieldTest.kt @@ -1,10 +1,16 @@ package kscience.kmath.structures +import kscience.kmath.operations.internal.FieldVerifier +import kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals +internal class NDFieldTest { + @Test + fun verify() { + (NDField.real(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } + } -class NDFieldTest { @Test fun testStrides() { val ndArray = NDElement.real(intArrayOf(10, 10)) { (it[0] + it[1]).toDouble() } From 12d64220659051a9723446c4f0b86559b1a1d199 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 21:43:04 +0700 Subject: [PATCH 22/55] Fix wrong package --- .../jsMain/kotlin/kscience/kmath/estree/Codegen.kt | 1 + .../kscience/kmath/estree/internal/JSBuilder.kt | 11 ----------- .../kmath/estree/internal/astring/astring.kt | 2 +- .../estree/internal/estree/estree.extensions.kt | 12 ------------ .../kscience/kmath/estree/internal/estree/estree.kt | 2 +- 5 files changed, 3 insertions(+), 25 deletions(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt index d10c9c0cf..50454fa34 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt @@ -4,6 +4,7 @@ import estree.* import kscience.kmath.ast.MST import kscience.kmath.ast.MstExpression import kscience.kmath.estree.internal.JSBuilder +import kscience.kmath.estree.internal.estree.BaseExpression import kscience.kmath.expressions.Expression import kscience.kmath.operations.Algebra import kscience.kmath.operations.NumericAlgebra diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt index b38be085d..a55ac62a4 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt @@ -1,18 +1,7 @@ package kscience.kmath.estree.internal import kscience.kmath.estree.internal.astring.generate -import estree.* import kscience.kmath.estree.internal.estree.* -import kscience.kmath.estree.internal.estree.BlockStatement -import kscience.kmath.estree.internal.estree.FunctionExpression -import kscience.kmath.estree.internal.estree.Identifier -import kscience.kmath.estree.internal.estree.MemberExpression -import kscience.kmath.estree.internal.estree.Program -import kscience.kmath.estree.internal.estree.ReturnStatement -import kscience.kmath.estree.internal.estree.SimpleCallExpression -import kscience.kmath.estree.internal.estree.SimpleLiteral -import kscience.kmath.estree.internal.estree.VariableDeclaration -import kscience.kmath.estree.internal.estree.VariableDeclarator import kscience.kmath.expressions.Expression import kscience.kmath.expressions.Symbol diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt index 4ef3acf20..cf0a8de25 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt @@ -3,7 +3,7 @@ package kscience.kmath.estree.internal.astring -import estree.BaseNode +import kscience.kmath.estree.internal.estree.BaseNode internal external interface Options { var indent: String? diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt index 951cd9ef8..5bc197d0c 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt @@ -1,17 +1,5 @@ package kscience.kmath.estree.internal.estree -import estree.* -import estree.BlockStatement -import estree.FunctionExpression -import estree.Identifier -import estree.MemberExpression -import estree.Program -import estree.ReturnStatement -import estree.SimpleCallExpression -import estree.SimpleLiteral -import estree.VariableDeclaration -import estree.VariableDeclarator - internal fun Program(sourceType: String, vararg body: dynamic) = object : Program { override var type = "Program" override var sourceType = sourceType diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt index 8d894a1b1..a5385d1ee 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt @@ -1,4 +1,4 @@ -package estree +package kscience.kmath.estree.internal.estree import kotlin.js.RegExp From 7002bdb5bdd37fce26c0b63195a3b6db462082c7 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 21:45:02 +0700 Subject: [PATCH 23/55] Remove redundant suppression --- .../jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt index a55ac62a4..6845437b3 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt @@ -7,7 +7,7 @@ import kscience.kmath.expressions.Symbol internal class JSBuilder(val bodyCallback: JSBuilder.() -> BaseExpression) { private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression { - @Suppress("UNUSED_VARIABLE", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") + @Suppress("UNUSED_VARIABLE") override fun invoke(arguments: Map): T { val e = executable val c = constants From 306eaecdb1cd323525ff0be855e55ada4a4a6160 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 20 Dec 2020 21:55:20 +0700 Subject: [PATCH 24/55] Remove invalid import --- kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt index 50454fa34..f5727fb16 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt @@ -1,6 +1,5 @@ package kscience.kmath.estree -import estree.* import kscience.kmath.ast.MST import kscience.kmath.ast.MstExpression import kscience.kmath.estree.internal.JSBuilder From cfc13cda8fbc97137ee9345942531611b3aa5367 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 12:57:50 +0700 Subject: [PATCH 25/55] Rename files and JSBuilder --- .../kotlin/kscience/kmath/estree/{Codegen.kt => estree.kt} | 6 +++--- .../estree/internal/{JSBuilder.kt => ESTreeBuilder.kt} | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/{Codegen.kt => estree.kt} (92%) rename kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/{JSBuilder.kt => ESTreeBuilder.kt} (96%) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt similarity index 92% rename from kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt rename to kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt index f5727fb16..5036e96c0 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/Codegen.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt @@ -2,7 +2,7 @@ package kscience.kmath.estree import kscience.kmath.ast.MST import kscience.kmath.ast.MstExpression -import kscience.kmath.estree.internal.JSBuilder +import kscience.kmath.estree.internal.ESTreeBuilder import kscience.kmath.estree.internal.estree.BaseExpression import kscience.kmath.expressions.Expression import kscience.kmath.operations.Algebra @@ -11,7 +11,7 @@ import kscience.kmath.operations.RealField @PublishedApi internal fun MST.compileWith(algebra: Algebra): Expression { - fun JSBuilder.visit(node: MST): BaseExpression = when (node) { + fun ESTreeBuilder.visit(node: MST): BaseExpression = when (node) { is MST.Symbolic -> { val symbol = try { algebra.symbol(node.value) @@ -57,7 +57,7 @@ internal fun MST.compileWith(algebra: Algebra): Expression { } } - return JSBuilder { visit(this@compileWith) }.instance + return ESTreeBuilder { visit(this@compileWith) }.instance } diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt similarity index 96% rename from kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt rename to kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt index 6845437b3..e58ad54b3 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/JSBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -5,7 +5,7 @@ import kscience.kmath.estree.internal.estree.* import kscience.kmath.expressions.Expression import kscience.kmath.expressions.Symbol -internal class JSBuilder(val bodyCallback: JSBuilder.() -> BaseExpression) { +internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExpression) { private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression { @Suppress("UNUSED_VARIABLE") override fun invoke(arguments: Map): T { From d657f40e3f84542de429ac314a1c62a3eaad2304 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 12:58:35 +0700 Subject: [PATCH 26/55] Fix KDoc comments --- kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt index 5036e96c0..f9996b61a 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt @@ -62,7 +62,7 @@ internal fun MST.compileWith(algebra: Algebra): Expression { /** - * Compiles an [MST] to ASM using given algebra. + * Compiles an [MST] to ESTree generated expression using given algebra. * * @author Alexander Nozik. */ @@ -70,7 +70,7 @@ public fun Algebra.expression(mst: MST): Expression = mst.compileWith(this) /** - * Optimizes performance of an [MstExpression] using ASM codegen. + * Optimizes performance of an [MstExpression] by compiling it into ESTree generated expression. * * @author Alexander Nozik. */ From 46ac73d2c167be6d3cdb154b755f03c7d1f04817 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 13:11:12 +0700 Subject: [PATCH 27/55] Add undefined handling in constant insertion --- .../kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt index e58ad54b3..349686b83 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -40,9 +40,10 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp private val keys = mutableListOf() fun constant(value: Any?) = when { - value == null || jsTypeOf(value) == "number" || jsTypeOf(value) == "string" || jsTypeOf(value) == "boolean" -> { + value == null || jsTypeOf(value) == "number" || jsTypeOf(value) == "string" || jsTypeOf(value) == "boolean" -> SimpleLiteral(value) - } + + jsType(value) == "undefined" -> Identifier("undefined") else -> { val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex From 1ab6702bb4eac6a5ef1381bac29d3d3c34ac96b2 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 13:11:44 +0700 Subject: [PATCH 28/55] Delete unused property --- .../kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt index 349686b83..e03a71123 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -37,7 +37,6 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp } private val constants = mutableListOf() - private val keys = mutableListOf() fun constant(value: Any?) = when { value == null || jsTypeOf(value) == "number" || jsTypeOf(value) == "string" || jsTypeOf(value) == "boolean" -> From d521fa0d8d7e0be670d019431209fad8ca8ab4f5 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 13:15:01 +0700 Subject: [PATCH 29/55] Fix wrong function name --- .../kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt index e03a71123..e1823813a 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -42,7 +42,7 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp value == null || jsTypeOf(value) == "number" || jsTypeOf(value) == "string" || jsTypeOf(value) == "boolean" -> SimpleLiteral(value) - jsType(value) == "undefined" -> Identifier("undefined") + jsTypeOf(value) == "undefined" -> Identifier("undefined") else -> { val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex From 2310aca9dbaf151a00119bd66fc440799f8281f2 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 13:42:12 +0700 Subject: [PATCH 30/55] Improve consistency of operations in MstAlgebra --- .../kotlin/kscience/kmath/ast/MstAlgebra.kt | 20 +++++++++++++------ .../kscience/kmath/operations/Algebra.kt | 4 ++-- .../kmath/operations/NumberAlgebra.kt | 5 ++--- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt index 96703ffb8..970ef3570 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt @@ -25,7 +25,9 @@ public object MstSpace : Space, NumericAlgebra { public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value) public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value) public override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) - public override fun MST.unaryMinus(): MST = unaryOperation(SpaceOperations.MINUS_OPERATION)(this) + public override operator fun MST.unaryPlus(): MST = unaryOperation(SpaceOperations.PLUS_OPERATION)(this) + public override operator fun MST.unaryMinus(): MST = unaryOperation(SpaceOperations.MINUS_OPERATION)(this) + public override operator fun MST.minus(b: MST): MST = binaryOperation(SpaceOperations.MINUS_OPERATION)(this, b) public override fun multiply(a: MST, k: Number): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k)) @@ -41,17 +43,19 @@ public object MstSpace : Space, NumericAlgebra { * [Ring] over [MST] nodes. */ public object MstRing : Ring, NumericAlgebra { - override val zero: MST.Numeric + public override val zero: MST.Numeric get() = MstSpace.zero - override val one: MST.Numeric by lazy { number(1.0) } + public override val one: MST.Numeric by lazy { number(1.0) } public override fun number(value: Number): MST.Numeric = MstSpace.number(value) public override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value) public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b) public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, b) - public override fun MST.unaryMinus(): MST = MstSpace.unaryOperation(SpaceOperations.MINUS_OPERATION)(this) + public override operator fun MST.unaryPlus(): MST = MstSpace { this@unaryPlus } + public override operator fun MST.unaryMinus(): MST = MstSpace { -this@unaryMinus } + public override operator fun MST.minus(b: MST): MST = MstSpace { this@minus - b } public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstSpace.binaryOperation(operation) @@ -76,7 +80,9 @@ public object MstField : Field { public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) public override fun divide(a: MST, b: MST): MST.Binary = binaryOperation(FieldOperations.DIV_OPERATION)(a, b) - public override fun MST.unaryMinus(): MST = MstSpace.unaryOperation(SpaceOperations.MINUS_OPERATION)(this) + public override operator fun MST.unaryPlus(): MST = MstRing { this@unaryPlus } + public override operator fun MST.unaryMinus(): MST = MstRing { -this@unaryMinus } + public override operator fun MST.minus(b: MST): MST = MstRing { this@minus - b } public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperation(operation) @@ -111,7 +117,9 @@ public object MstExtendedField : ExtendedField { public override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) - public override fun MST.unaryMinus(): MST = MstSpace.unaryOperation(SpaceOperations.MINUS_OPERATION)(this) + public override operator fun MST.unaryPlus(): MST = MstField { this@unaryPlus } + public override operator fun MST.unaryMinus(): MST = MstField { -this@unaryMinus } + public override operator fun MST.minus(b: MST): MST = MstField { this@minus - b } public override fun power(arg: MST, pow: Number): MST.Binary = binaryOperation(PowerOperations.POW_OPERATION)(arg, number(pow)) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index 6cf9eeb78..f1ceb8858 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -275,12 +275,12 @@ public interface SpaceOperations : Algebra { public companion object { /** - * The identifier of addition. + * The identifier of addition and unary positive. */ public const val PLUS_OPERATION: String = "+" /** - * The identifier of subtraction (and negation). + * The identifier of subtraction and unary negation. */ public const val MINUS_OPERATION: String = "-" } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt index cd2bd0417..84d89b7eb 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt @@ -1,6 +1,5 @@ package kscience.kmath.operations -import kotlin.math.abs import kotlin.math.pow as kpow /** @@ -249,10 +248,10 @@ public object ByteRing : Ring, Norm { @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object LongRing : Ring, Norm { public override val zero: Long - get() = 0 + get() = 0L public override val one: Long - get() = 1 + get() = 1L public override inline fun add(a: Long, b: Long): Long = a + b public override inline fun multiply(a: Long, k: Number): Long = a * k.toLong() From c738fb1f2a5e85ee1b5ec7166d9e4aa860971627 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 13:44:52 +0700 Subject: [PATCH 31/55] Make return types more specific in MstAlgebra.kt --- .../kotlin/kscience/kmath/ast/MstAlgebra.kt | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt index 970ef3570..edbd7f92b 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt @@ -25,9 +25,9 @@ public object MstSpace : Space, NumericAlgebra { public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value) public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value) public override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST = unaryOperation(SpaceOperations.PLUS_OPERATION)(this) - public override operator fun MST.unaryMinus(): MST = unaryOperation(SpaceOperations.MINUS_OPERATION)(this) - public override operator fun MST.minus(b: MST): MST = binaryOperation(SpaceOperations.MINUS_OPERATION)(this, b) + public override operator fun MST.unaryPlus(): MST.Unary = unaryOperation(SpaceOperations.PLUS_OPERATION)(this) + public override operator fun MST.unaryMinus(): MST.Unary = unaryOperation(SpaceOperations.MINUS_OPERATION)(this) + public override operator fun MST.minus(b: MST): MST.Binary = binaryOperation(SpaceOperations.MINUS_OPERATION)(this, b) public override fun multiply(a: MST, k: Number): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k)) @@ -53,9 +53,9 @@ public object MstRing : Ring, NumericAlgebra { public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b) public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST = MstSpace { this@unaryPlus } - public override operator fun MST.unaryMinus(): MST = MstSpace { -this@unaryMinus } - public override operator fun MST.minus(b: MST): MST = MstSpace { this@minus - b } + public override operator fun MST.unaryPlus(): MST.Unary = MstSpace { +this@unaryPlus } + public override operator fun MST.unaryMinus(): MST.Unary = MstSpace { -this@unaryMinus } + public override operator fun MST.minus(b: MST): MST.Binary = MstSpace { this@minus - b } public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstSpace.binaryOperation(operation) @@ -80,9 +80,9 @@ public object MstField : Field { public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) public override fun divide(a: MST, b: MST): MST.Binary = binaryOperation(FieldOperations.DIV_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST = MstRing { this@unaryPlus } - public override operator fun MST.unaryMinus(): MST = MstRing { -this@unaryMinus } - public override operator fun MST.minus(b: MST): MST = MstRing { this@minus - b } + public override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } + public override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } + public override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b } public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperation(operation) @@ -100,7 +100,7 @@ public object MstExtendedField : ExtendedField { public override val one: MST.Numeric get() = MstField.one - public override fun symbol(value: String): MST = MstField.symbol(value) + public override fun symbol(value: String): MST.Symbolic = MstField.symbol(value) public override fun sin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.SIN_OPERATION)(arg) public override fun cos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.COS_OPERATION)(arg) public override fun tan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.TAN_OPERATION)(arg) @@ -117,9 +117,9 @@ public object MstExtendedField : ExtendedField { public override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) - public override operator fun MST.unaryPlus(): MST = MstField { this@unaryPlus } - public override operator fun MST.unaryMinus(): MST = MstField { -this@unaryMinus } - public override operator fun MST.minus(b: MST): MST = MstField { this@minus - b } + public override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus } + public override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus } + public override operator fun MST.minus(b: MST): MST.Binary = MstField { this@minus - b } public override fun power(arg: MST, pow: Number): MST.Binary = binaryOperation(PowerOperations.POW_OPERATION)(arg, number(pow)) From d631c048c746fab1200ce853086b45e9ea6b0ecb Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 16:00:51 +0700 Subject: [PATCH 32/55] Fix minor problems, update README --- kmath-ast/README.md | 41 +++++++++++++++---- .../kotlin/kscience/kmath/ast/MstAlgebra.kt | 4 +- .../kscience/kmath/asm/internal/AsmBuilder.kt | 13 +++++- .../kotlin/kscience/kmath/ast/AsmTest.kt | 2 - .../kmath/ast/ParserPrecedenceTest.kt | 2 - .../kscience/kmath/operations/Algebra.kt | 4 +- 6 files changed, 48 insertions(+), 18 deletions(-) diff --git a/kmath-ast/README.md b/kmath-ast/README.md index 043224800..ea89883ab 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -38,7 +38,9 @@ This subproject implements the following features: > ``` > -## Dynamic Expression Code Generation with ObjectWeb ASM +## Dynamic expression code generation + +### On JVM `kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a special implementation of `Expression` with implemented `invoke` function. @@ -55,19 +57,20 @@ RealField.mstInField { symbol("x") + 2 }.compile() package kscience.kmath.asm.generated; import java.util.Map; +import kotlin.jvm.functions.Function2; import kscience.kmath.asm.internal.MapIntrinsics; import kscience.kmath.expressions.Expression; -import kscience.kmath.operations.RealField; +import kscience.kmath.expressions.Symbol; -public final class AsmCompiledExpression_1073786867_0 implements Expression { - private final RealField algebra; +public final class AsmCompiledExpression_45045_0 implements Expression { + private final Object[] constants; - public final Double invoke(Map arguments) { - return (Double)this.algebra.add(((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(), 2.0D); + public final Double invoke(Map arguments) { + return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2); } - public AsmCompiledExpression_1073786867_0(RealField algebra) { - this.algebra = algebra; + public AsmCompiledExpression_45045_0(Object[] constants) { + this.constants = constants; } } @@ -82,10 +85,30 @@ RealField.mstInField { symbol("x") + 2 }.compile() RealField.expression("x+2".parseMath()) ``` -### Known issues +#### Known issues - The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead. - This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. Contributed by [Iaroslav Postovalov](https://github.com/CommanderTvis). + +### On JS + +A similar feature is also available on JS. + +```kotlin +RealField.mstInField { symbol("x") + 2 }.compile() +``` + +The code above returns expression implemented with such a JS function: + +```js +var executable = function (constants, arguments) { + return constants[1](constants[0](arguments, "x"), 2); +}; +``` + +#### Known issues + +- This feature uses `eval` which can be unavailable in several environments. diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt index edbd7f92b..55d5b659d 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt @@ -27,7 +27,9 @@ public object MstSpace : Space, NumericAlgebra { public override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) public override operator fun MST.unaryPlus(): MST.Unary = unaryOperation(SpaceOperations.PLUS_OPERATION)(this) public override operator fun MST.unaryMinus(): MST.Unary = unaryOperation(SpaceOperations.MINUS_OPERATION)(this) - public override operator fun MST.minus(b: MST): MST.Binary = binaryOperation(SpaceOperations.MINUS_OPERATION)(this, b) + + public override operator fun MST.minus(b: MST): MST.Binary = + binaryOperation(SpaceOperations.MINUS_OPERATION)(this, b) public override fun multiply(a: MST, k: Number): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k)) 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 882b95bf0..af7dc61b9 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 @@ -2,13 +2,16 @@ package kscience.kmath.asm.internal import kscience.kmath.asm.internal.AsmBuilder.ClassLoader import kscience.kmath.ast.MST +import kscience.kmath.ast.mstInField import kscience.kmath.expressions.Expression +import kscience.kmath.operations.RealField import org.objectweb.asm.* import org.objectweb.asm.Opcodes.* import org.objectweb.asm.Type.* import org.objectweb.asm.commons.InstructionAdapter import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType +import java.lang.reflect.Modifier import java.util.stream.Collectors.toMap import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -82,7 +85,7 @@ internal class AsmBuilder( ACC_PUBLIC or ACC_FINAL, "invoke", getMethodDescriptor(tType, MAP_TYPE), - "(L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", + "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}${if (Modifier.isFinal(classOfT.modifiers)) "" else "+"}${tType.descriptor}>;)${tType.descriptor}", null, ).instructionAdapter { invokeMethodVisitor = this @@ -159,7 +162,7 @@ internal class AsmBuilder( "", getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), null, - null + null, ).instructionAdapter { val l0 = label() load(0, classType) @@ -190,6 +193,7 @@ internal class AsmBuilder( } val cls = classLoader.defineClass(className, classWriter.toByteArray()) + java.io.File("dump.class").writeBytes(classWriter.toByteArray()) val l = MethodHandles.publicLookup() if (hasConstants) @@ -334,5 +338,10 @@ internal class AsmBuilder( * ASM type for MapIntrinsics. */ val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("kscience/kmath/asm/internal/MapIntrinsics") } + + /** + * ASM Type for [kscience.kmath.expressions.Symbol]. + */ + val SYMBOL_TYPE: Type by lazy { getObjectType("kscience/kmath/expressions/Symbol") } } } diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt index 1ca8aa5dd..992f4024e 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt @@ -2,8 +2,6 @@ package kscience.kmath.ast import kscience.kmath.asm.compile import kscience.kmath.asm.expression -import kscience.kmath.ast.mstInField -import kscience.kmath.ast.parseMath import kscience.kmath.expressions.invoke import kscience.kmath.operations.Complex import kscience.kmath.operations.ComplexField diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserPrecedenceTest.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserPrecedenceTest.kt index 1844a0991..561fe51bd 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserPrecedenceTest.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserPrecedenceTest.kt @@ -1,7 +1,5 @@ package kscience.kmath.ast -import kscience.kmath.ast.evaluate -import kscience.kmath.ast.parseMath import kscience.kmath.operations.Field import kscience.kmath.operations.RealField import kotlin.test.Test diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index f1ceb8858..d2cf8e0dd 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -275,12 +275,12 @@ public interface SpaceOperations : Algebra { public companion object { /** - * The identifier of addition and unary positive. + * The identifier of addition and unary positive operator. */ public const val PLUS_OPERATION: String = "+" /** - * The identifier of subtraction and unary negation. + * The identifier of subtraction and unary negative operator. */ public const val MINUS_OPERATION: String = "-" } From 1b0f462e54a3ab2f61a09978b63fef7bf479b7d6 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 17:49:32 +0700 Subject: [PATCH 33/55] Reformat build.gradle.kts --- kmath-ast/build.gradle.kts | 8 +++++--- .../kotlin/kscience/kmath/asm/internal/AsmBuilder.kt | 2 -- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 1f4a87b12..574793124 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -1,3 +1,5 @@ +import ru.mipt.npm.gradle.Maturity + plugins { id("ru.mipt.npm.mpp") } @@ -38,6 +40,6 @@ kotlin.sourceSets { } } -readme{ - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE -} \ No newline at end of file +readme { + maturity = Maturity.PROTOTYPE +} 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 af7dc61b9..1edbed28d 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 @@ -2,9 +2,7 @@ package kscience.kmath.asm.internal import kscience.kmath.asm.internal.AsmBuilder.ClassLoader import kscience.kmath.ast.MST -import kscience.kmath.ast.mstInField import kscience.kmath.expressions.Expression -import kscience.kmath.operations.RealField import org.objectweb.asm.* import org.objectweb.asm.Opcodes.* import org.objectweb.asm.Type.* From 50b62f8a3b5a59ddabe1f17551643bac2919f66a Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 18:02:02 +0700 Subject: [PATCH 34/55] Update readme --- README.md | 13 ++++- kmath-ast/README.md | 44 ++++++++++------- kmath-ast/build.gradle.kts | 37 ++++++++++++++ kmath-ast/docs/README-TEMPLATE.md | 80 +++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 20 deletions(-) create mode 100644 kmath-ast/docs/README-TEMPLATE.md diff --git a/README.md b/README.md index 50a916d2c..0899f77cc 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,16 @@ submit a feature request if you want something to be implemented first. * ### [kmath-ast](kmath-ast) > > -> **Maturity**: EXPERIMENTAL +> **Maturity**: PROTOTYPE +> +> **Features:** +> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser +> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation +> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure +> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter +> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler +> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler +
* ### [kmath-commons](kmath-commons) @@ -122,7 +131,7 @@ submit a feature request if you want something to be implemented first. * ### [kmath-dimensions](kmath-dimensions) > > -> **Maturity**: EXPERIMENTAL +> **Maturity**: PROTOTYPE
* ### [kmath-ejml](kmath-ejml) diff --git a/kmath-ast/README.md b/kmath-ast/README.md index ea89883ab..bddc1c563 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -2,56 +2,66 @@ This subproject implements the following features: -- Expression Language and its parser. -- MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation. -- Type-safe builder for MST. -- Evaluating expressions by traversing MST. + - [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser + - [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation + - [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure + - [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter + - [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler + - [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler + > #### Artifact: -> This module is distributed in the artifact `kscience.kmath:kmath-ast:0.1.4-dev-8`. -> +> +> This module artifact: `kscience.kmath:kmath-ast:0.2.0-dev-4`. +> +> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion) +> +> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-ast/_latestVersion) +> > **Gradle:** > > ```gradle > repositories { +> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } > maven { url 'https://dl.bintray.com/mipt-npm/kscience' } > maven { url 'https://dl.bintray.com/mipt-npm/dev' } -> maven { url https://dl.bintray.com/hotkeytlt/maven' } +> maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + > } > > dependencies { -> implementation 'kscience.kmath:kmath-ast:0.1.4-dev-8' +> implementation 'kscience.kmath:kmath-ast:0.2.0-dev-4' > } > ``` > **Gradle Kotlin DSL:** > > ```kotlin > repositories { +> maven("https://dl.bintray.com/kotlin/kotlin-eap") > maven("https://dl.bintray.com/mipt-npm/kscience") > maven("https://dl.bintray.com/mipt-npm/dev") > maven("https://dl.bintray.com/hotkeytlt/maven") > } > > dependencies { -> implementation("kscience.kmath:kmath-ast:0.1.4-dev-8") +> implementation("kscience.kmath:kmath-ast:0.2.0-dev-4") > } > ``` -> ## Dynamic expression code generation ### On JVM -`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds -a special implementation of `Expression` with implemented `invoke` function. +`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds +a special implementation of `Expression` with implemented `invoke` function. -For example, the following builder: +For example, the following builder: ```kotlin RealField.mstInField { symbol("x") + 2 }.compile() ``` -… leads to generation of bytecode, which can be decompiled to the following Java class: +… leads to generation of bytecode, which can be decompiled to the following Java class: ```java package kscience.kmath.asm.generated; @@ -78,7 +88,7 @@ public final class AsmCompiledExpression_45045_0 implements Expression { ### Example Usage -This API extends MST and MstExpression, so you may optimize as both of them: +This API extends MST and MstExpression, so you may optimize as both of them: ```kotlin RealField.mstInField { symbol("x") + 2 }.compile() @@ -88,11 +98,9 @@ RealField.expression("x+2".parseMath()) #### Known issues - The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid -class loading overhead. + class loading overhead. - This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. -Contributed by [Iaroslav Postovalov](https://github.com/CommanderTvis). - ### On JS A similar feature is also available on JS. diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 574793124..b2d027d35 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -42,4 +42,41 @@ kotlin.sourceSets { readme { maturity = Maturity.PROTOTYPE + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) + + feature( + id = "expression-language", + description = "Expression language and its parser", + ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt" + ) + + feature( + id = "mst", + description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation", + ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt" + ) + + feature( + id = "mst-building", + description = "MST building algebraic structure", + ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt" + ) + + feature( + id = "mst-interpreter", + description = "MST interpreter", + ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt" + ) + + feature( + id = "mst-jvm-codegen", + description = "Dynamic MST to JVM bytecode compiler", + ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt" + ) + + feature( + id = "mst-js-codegen", + description = "Dynamic MST to JS compiler", + ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt" + ) } diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md new file mode 100644 index 000000000..3227a2ad3 --- /dev/null +++ b/kmath-ast/docs/README-TEMPLATE.md @@ -0,0 +1,80 @@ +# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`) + +This subproject implements the following features: + +${features} + +${artifact} + +## Dynamic expression code generation + +### On JVM + +`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds +a special implementation of `Expression` with implemented `invoke` function. + +For example, the following builder: + +```kotlin +RealField.mstInField { symbol("x") + 2 }.compile() +``` + +… leads to generation of bytecode, which can be decompiled to the following Java class: + +```java +package kscience.kmath.asm.generated; + +import java.util.Map; +import kotlin.jvm.functions.Function2; +import kscience.kmath.asm.internal.MapIntrinsics; +import kscience.kmath.expressions.Expression; +import kscience.kmath.expressions.Symbol; + +public final class AsmCompiledExpression_45045_0 implements Expression { + private final Object[] constants; + + public final Double invoke(Map arguments) { + return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2); + } + + public AsmCompiledExpression_45045_0(Object[] constants) { + this.constants = constants; + } +} + +``` + +### Example Usage + +This API extends MST and MstExpression, so you may optimize as both of them: + +```kotlin +RealField.mstInField { symbol("x") + 2 }.compile() +RealField.expression("x+2".parseMath()) +``` + +#### Known issues + +- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid + class loading overhead. +- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. + +### On JS + +A similar feature is also available on JS. + +```kotlin +RealField.mstInField { symbol("x") + 2 }.compile() +``` + +The code above returns expression implemented with such a JS function: + +```js +var executable = function (constants, arguments) { + return constants[1](constants[0](arguments, "x"), 2); +}; +``` + +#### Known issues + +- This feature uses `eval` which can be unavailable in several environments. From 1a5efd0a1730d52fa1a10540a3cf169284ff6413 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 18:17:24 +0700 Subject: [PATCH 35/55] Improve ASM and ESTree tests quality --- ...> TestESTreeConsistencyWithInterpreter.kt} | 43 ++++++++++++++----- ...ions.kt => TestESTreeOperationsSupport.kt} | 23 ++-------- .../kmath/estree/TestESTreeVariables.kt | 4 +- ...t => TestAsmConsistencyWithInterpreter.kt} | 43 ++++++++++++++----- ...essions.kt => TestAsmOperationsSupport.kt} | 2 +- .../kscience/kmath/asm/TestAsmVariables.kt | 4 +- .../kotlin/kscience/kmath/ast/AsmTest.kt | 23 ---------- 7 files changed, 73 insertions(+), 69 deletions(-) rename kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/{TestESTreeAlgebras.kt => TestESTreeConsistencyWithInterpreter.kt} (68%) rename kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/{TestESTreeExpressions.kt => TestESTreeOperationsSupport.kt} (56%) rename kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/{TestAsmAlgebras.kt => TestAsmConsistencyWithInterpreter.kt} (69%) rename kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/{TestAsmExpressions.kt => TestAsmOperationsSupport.kt} (96%) delete mode 100644 kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeAlgebras.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt similarity index 68% rename from kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeAlgebras.kt rename to kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt index 09a8ab3e5..242a4154d 100644 --- a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeAlgebras.kt +++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt @@ -1,18 +1,18 @@ package kscience.kmath.estree -import kscience.kmath.ast.mstInField -import kscience.kmath.ast.mstInRing -import kscience.kmath.ast.mstInSpace +import kscience.kmath.ast.* import kscience.kmath.expressions.invoke import kscience.kmath.operations.ByteRing +import kscience.kmath.operations.ComplexField import kscience.kmath.operations.RealField +import kscience.kmath.operations.toComplex import kotlin.test.Test import kotlin.test.assertEquals -internal class TestESTreeAlgebras { +internal class TestESTreeConsistencyWithInterpreter { @Test - fun space() { - val res1 = ByteRing.mstInSpace { + fun mstSpace() { + val res1 = MstSpace.mstInSpace { binaryOperation("+")( unaryOperation("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( @@ -23,9 +23,9 @@ internal class TestESTreeAlgebras { number(1) ) + symbol("x") + zero - }("x" to 2.toByte()) + }("x" to MST.Numeric(2)) - val res2 = ByteRing.mstInSpace { + val res2 = MstSpace.mstInSpace { binaryOperation("+")( unaryOperation("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( @@ -36,13 +36,13 @@ internal class TestESTreeAlgebras { number(1) ) + symbol("x") + zero - }.compile()("x" to 2.toByte()) + }.compile()("x" to MST.Numeric(2)) assertEquals(res1, res2) } @Test - fun ring() { + fun byteRing() { val res1 = ByteRing.mstInRing { binaryOperation("+")( unaryOperation("+")( @@ -72,7 +72,7 @@ internal class TestESTreeAlgebras { } @Test - fun field() { + fun realField() { val res1 = RealField.mstInField { +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 @@ -91,4 +91,25 @@ internal class TestESTreeAlgebras { assertEquals(res1, res2) } + + @Test + fun complexField() { + val res1 = ComplexField.mstInField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + }("x" to 2.0.toComplex()) + + val res2 = ComplexField.mstInField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + }.compile()("x" to 2.0.toComplex()) + + assertEquals(res1, res2) + } } diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeExpressions.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeOperationsSupport.kt similarity index 56% rename from kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeExpressions.kt rename to kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeOperationsSupport.kt index 3dc259cb3..72a4669d9 100644 --- a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeExpressions.kt +++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeOperationsSupport.kt @@ -3,17 +3,13 @@ package kscience.kmath.estree import kscience.kmath.ast.mstInExtendedField import kscience.kmath.ast.mstInField import kscience.kmath.ast.mstInSpace -import kscience.kmath.expressions.Expression -import kscience.kmath.expressions.StringSymbol import kscience.kmath.expressions.invoke import kscience.kmath.operations.RealField -import kotlin.math.pow import kotlin.random.Random import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.time.measureTime -internal class TestESTreeExpressions { +internal class TestESTreeOperationsSupport { @Test fun testUnaryOperationInvocation() { val expression = RealField.mstInSpace { -symbol("x") }.compile() @@ -36,21 +32,10 @@ internal class TestESTreeExpressions { @Test fun testMultipleCalls() { - val e1 = - RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile() - - val e2 = Expression { a -> - val x = a.getValue(StringSymbol("x")) - kotlin.math.sin(x).pow(4) - 6 * x / kotlin.math.tanh(x) - } - - var r = Random(0) + val e = RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile() + val r = Random(0) var s = 0.0 - measureTime { repeat(1000000) { s += e1("x" to r.nextDouble()) } }.also(::println) - println(s) - s = 0.0 - r = Random(0) - measureTime { repeat(1000000) { s += e2("x" to r.nextDouble()) } }.also(::println) + repeat(1000000) { s += e("x" to r.nextDouble()) } println(s) } } diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt index b6f59247d..846120ee2 100644 --- a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt +++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt @@ -9,13 +9,13 @@ import kotlin.test.assertFailsWith internal class TestESTreeVariables { @Test - fun testVariableWithoutDefault() { + fun testVariable() { val expr = ByteRing.mstInRing { symbol("x") }.compile() assertEquals(1.toByte(), expr("x" to 1.toByte())) } @Test - fun testVariableWithoutDefaultFails() { + fun testUndefinedVariableFails() { val expr = ByteRing.mstInRing { symbol("x") }.compile() assertFailsWith { expr() } } diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt similarity index 69% rename from kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt rename to kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt index a1687c1c7..013ae789d 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt @@ -1,18 +1,18 @@ package kscience.kmath.asm -import kscience.kmath.ast.mstInField -import kscience.kmath.ast.mstInRing -import kscience.kmath.ast.mstInSpace +import kscience.kmath.ast.* import kscience.kmath.expressions.invoke import kscience.kmath.operations.ByteRing +import kscience.kmath.operations.ComplexField import kscience.kmath.operations.RealField +import kscience.kmath.operations.toComplex import kotlin.test.Test import kotlin.test.assertEquals -internal class TestAsmAlgebras { +internal class TestAsmConsistencyWithInterpreter { @Test - fun space() { - val res1 = ByteRing.mstInSpace { + fun mstSpace() { + val res1 = MstSpace.mstInSpace { binaryOperation("+")( unaryOperation("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( @@ -23,9 +23,9 @@ internal class TestAsmAlgebras { number(1) ) + symbol("x") + zero - }("x" to 2.toByte()) + }("x" to MST.Numeric(2)) - val res2 = ByteRing.mstInSpace { + val res2 = MstSpace.mstInSpace { binaryOperation("+")( unaryOperation("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( @@ -36,13 +36,13 @@ internal class TestAsmAlgebras { number(1) ) + symbol("x") + zero - }.compile()("x" to 2.toByte()) + }.compile()("x" to MST.Numeric(2)) assertEquals(res1, res2) } @Test - fun ring() { + fun byteRing() { val res1 = ByteRing.mstInRing { binaryOperation("+")( unaryOperation("+")( @@ -72,7 +72,7 @@ internal class TestAsmAlgebras { } @Test - fun field() { + fun realField() { val res1 = RealField.mstInField { +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 @@ -91,4 +91,25 @@ internal class TestAsmAlgebras { assertEquals(res1, res2) } + + @Test + fun complexField() { + val res1 = ComplexField.mstInField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + }("x" to 2.0.toComplex()) + + val res2 = ComplexField.mstInField { + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + + number(1), + number(1) / 2 + number(2.0) * one + ) + zero + }.compile()("x" to 2.0.toComplex()) + + assertEquals(res1, res2) + } } diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmOperationsSupport.kt similarity index 96% rename from kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt rename to kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmOperationsSupport.kt index acd9e21ea..2ce52aa87 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmOperationsSupport.kt @@ -9,7 +9,7 @@ import kotlin.random.Random import kotlin.test.Test import kotlin.test.assertEquals -internal class TestAsmExpressions { +internal class TestAsmOperationsSupport { @Test fun testUnaryOperationInvocation() { val expression = RealField.mstInSpace { -symbol("x") }.compile() diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt index 0ebc31be4..c91568dbf 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt @@ -9,13 +9,13 @@ import kotlin.test.assertFailsWith internal class TestAsmVariables { @Test - fun testVariableWithoutDefault() { + fun testVariable() { val expr = ByteRing.mstInRing { symbol("x") }.compile() assertEquals(1.toByte(), expr("x" to 1.toByte())) } @Test - fun testVariableWithoutDefaultFails() { + fun testUndefinedVariableFails() { val expr = ByteRing.mstInRing { symbol("x") }.compile() assertFailsWith { expr() } } diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt deleted file mode 100644 index 992f4024e..000000000 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt +++ /dev/null @@ -1,23 +0,0 @@ -package kscience.kmath.ast - -import kscience.kmath.asm.compile -import kscience.kmath.asm.expression -import kscience.kmath.expressions.invoke -import kscience.kmath.operations.Complex -import kscience.kmath.operations.ComplexField -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class AsmTest { - @Test - fun `compile MST`() { - val res = ComplexField.expression("2+2*(2+2)".parseMath())() - assertEquals(Complex(10.0, 0.0), res) - } - - @Test - fun `compile MSTExpression`() { - val res = ComplexField.mstInField { number(2) + number(2) * (number(2) + number(2)) }.compile()() - assertEquals(Complex(10.0, 0.0), res) - } -} From dab6b0e385791d960bb98a1624c22827a3cb5393 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 22:15:24 +0700 Subject: [PATCH 36/55] Add Space repository URL --- build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 561a2212b..90a39c531 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -38,3 +38,7 @@ readme { apiValidation { validationDisabled = true } + +ksciencePublish { + spaceRepo = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven" +} From 024800605f852eac9f3934961243c288adfa31aa Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 22 Dec 2020 22:20:30 +0700 Subject: [PATCH 37/55] Update ASM --- kmath-ast/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index b2d027d35..39de4256d 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -34,8 +34,8 @@ kotlin.sourceSets { jvmMain { dependencies { api("com.github.h0tk3y.betterParse:better-parse:0.4.0") - implementation("org.ow2.asm:asm:8.0.1") - implementation("org.ow2.asm:asm-commons:8.0.1") + implementation("org.ow2.asm:asm:9.0") + implementation("org.ow2.asm:asm-commons:9.0") } } } From 2c7cb1b04fc06ac68176aa05d5d2504754f94e53 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 5 Jan 2021 19:56:42 +0700 Subject: [PATCH 38/55] Rename ...Operation functions returning function to ...OperationFunction --- .../kotlin/kscience/kmath/ast/MST.kt | 12 +-- .../kotlin/kscience/kmath/ast/MstAlgebra.kt | 76 +++++++++---------- .../kscience/kmath/ast/MstExpression.kt | 4 +- .../kotlin/kscience/kmath/estree/estree.kt | 10 +-- .../TestESTreeConsistencyWithInterpreter.kt | 24 +++--- .../kmath/estree/TestESTreeSpecialization.kt | 14 ++-- .../jvmMain/kotlin/kscience/kmath/asm/asm.kt | 10 +-- .../asm/TestAsmConsistencyWithInterpreter.kt | 24 +++--- .../kmath/asm/TestAsmSpecialization.kt | 14 ++-- .../kotlin/kscience/kmath/ast/ParserTest.kt | 4 +- .../FunctionalExpressionAlgebra.kt | 62 +++++++-------- .../kscience/kmath/linear/MatrixContext.kt | 4 +- .../kscience/kmath/operations/Algebra.kt | 62 +++++++-------- .../kmath/operations/NumberAlgebra.kt | 16 ++-- 14 files changed, 168 insertions(+), 168 deletions(-) diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt index 4ff4d7354..6cf746722 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt @@ -57,22 +57,22 @@ public fun Algebra.evaluate(node: MST): T = when (node) { ?: error("Numeric nodes are not supported by $this") is MST.Symbolic -> symbol(node.value) - is MST.Unary -> unaryOperation(node.operation)(evaluate(node.value)) + is MST.Unary -> unaryOperationFunction(node.operation)(evaluate(node.value)) is MST.Binary -> when { - this !is NumericAlgebra -> binaryOperation(node.operation)(evaluate(node.left), evaluate(node.right)) + this !is NumericAlgebra -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right)) node.left is MST.Numeric && node.right is MST.Numeric -> { val number = RealField - .binaryOperation(node.operation) + .binaryOperationFunction(node.operation) .invoke(node.left.value.toDouble(), node.right.value.toDouble()) number(number) } - node.left is MST.Numeric -> leftSideNumberOperation(node.operation)(node.left.value, evaluate(node.right)) - node.right is MST.Numeric -> rightSideNumberOperation(node.operation)(evaluate(node.left), node.right.value) - else -> binaryOperation(node.operation)(evaluate(node.left), evaluate(node.right)) + node.left is MST.Numeric -> leftSideNumberOperationFunction(node.operation)(node.left.value, evaluate(node.right)) + node.right is MST.Numeric -> rightSideNumberOperationFunction(node.operation)(evaluate(node.left), node.right.value) + else -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right)) } } diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt index 55d5b659d..80b164a7c 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt @@ -9,10 +9,10 @@ public object MstAlgebra : NumericAlgebra { public override fun number(value: Number): MST.Numeric = MST.Numeric(value) public override fun symbol(value: String): MST.Symbolic = MST.Symbolic(value) - public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = { arg -> MST.Unary(operation, arg) } - public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = { left, right -> MST.Binary(operation, left, right) } } @@ -24,21 +24,21 @@ public object MstSpace : Space, NumericAlgebra { public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value) public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value) - public override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST.Unary = unaryOperation(SpaceOperations.PLUS_OPERATION)(this) - public override operator fun MST.unaryMinus(): MST.Unary = unaryOperation(SpaceOperations.MINUS_OPERATION)(this) + public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b) + public override operator fun MST.unaryPlus(): MST.Unary = unaryOperationFunction(SpaceOperations.PLUS_OPERATION)(this) + public override operator fun MST.unaryMinus(): MST.Unary = unaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this) public override operator fun MST.minus(b: MST): MST.Binary = - binaryOperation(SpaceOperations.MINUS_OPERATION)(this, b) + binaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this, b) public override fun multiply(a: MST, k: Number): MST.Binary = - binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k)) + binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(k)) - public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = - MstAlgebra.binaryOperation(operation) + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + MstAlgebra.binaryOperationFunction(operation) - public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = - MstAlgebra.unaryOperation(operation) + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + MstAlgebra.unaryOperationFunction(operation) } /** @@ -54,16 +54,16 @@ public object MstRing : Ring, NumericAlgebra { public override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value) public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b) public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k) - public override fun multiply(a: MST, b: MST): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION)(a, b) + public override fun multiply(a: MST, b: MST): MST.Binary = binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) public override operator fun MST.unaryPlus(): MST.Unary = MstSpace { +this@unaryPlus } public override operator fun MST.unaryMinus(): MST.Unary = MstSpace { -this@unaryMinus } public override operator fun MST.minus(b: MST): MST.Binary = MstSpace { this@minus - b } - public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = - MstSpace.binaryOperation(operation) + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + MstSpace.binaryOperationFunction(operation) - public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = - MstAlgebra.unaryOperation(operation) + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + MstAlgebra.unaryOperationFunction(operation) } /** @@ -81,15 +81,15 @@ public object MstField : Field { public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) - public override fun divide(a: MST, b: MST): MST.Binary = binaryOperation(FieldOperations.DIV_OPERATION)(a, b) + public override fun divide(a: MST, b: MST): MST.Binary = binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) public override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } public override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } public override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b } - public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = - MstRing.binaryOperation(operation) + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + MstRing.binaryOperationFunction(operation) - public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = MstRing.unaryOperation(operation) + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstRing.unaryOperationFunction(operation) } /** @@ -103,18 +103,18 @@ public object MstExtendedField : ExtendedField { get() = MstField.one public override fun symbol(value: String): MST.Symbolic = MstField.symbol(value) - public override fun sin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.SIN_OPERATION)(arg) - public override fun cos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.COS_OPERATION)(arg) - public override fun tan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.TAN_OPERATION)(arg) - public override fun asin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ASIN_OPERATION)(arg) - public override fun acos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ACOS_OPERATION)(arg) - public override fun atan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ATAN_OPERATION)(arg) - public override fun sinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.SINH_OPERATION)(arg) - public override fun cosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.COSH_OPERATION)(arg) - public override fun tanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.TANH_OPERATION)(arg) - public override fun asinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ASINH_OPERATION)(arg) - public override fun acosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ACOSH_OPERATION)(arg) - public override fun atanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ATANH_OPERATION)(arg) + public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) + public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) + public override fun tan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.TAN_OPERATION)(arg) + public override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) + public override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) + public override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) + public override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.SINH_OPERATION)(arg) + public override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.COSH_OPERATION)(arg) + public override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.TANH_OPERATION)(arg) + public override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ASINH_OPERATION)(arg) + public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ACOSH_OPERATION)(arg) + public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ATANH_OPERATION)(arg) public override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b) public override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) @@ -124,13 +124,13 @@ public object MstExtendedField : ExtendedField { public override operator fun MST.minus(b: MST): MST.Binary = MstField { this@minus - b } public override fun power(arg: MST, pow: Number): MST.Binary = - binaryOperation(PowerOperations.POW_OPERATION)(arg, number(pow)) + binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) - public override fun exp(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.EXP_OPERATION)(arg) - public override fun ln(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.LN_OPERATION)(arg) + public override fun exp(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) + public override fun ln(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - public override fun binaryOperation(operation: String): (left: MST, right: MST) -> MST.Binary = - MstField.binaryOperation(operation) + public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + MstField.binaryOperationFunction(operation) - public override fun unaryOperation(operation: String): (arg: MST) -> MST.Unary = MstField.unaryOperation(operation) + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstField.unaryOperationFunction(operation) } diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt index 4d1b65621..03d33aa2b 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt @@ -21,8 +21,8 @@ public class MstExpression>(public val algebra: A, public null } ?: arguments.getValue(StringSymbol(value)) - override fun unaryOperation(operation: String): (arg: T) -> T = algebra.unaryOperation(operation) - override fun binaryOperation(operation: String): (left: T, right: T) -> T = algebra.binaryOperation(operation) + override fun unaryOperationFunction(operation: String): (arg: T) -> T = algebra.unaryOperationFunction(operation) + override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = algebra.binaryOperationFunction(operation) @Suppress("UNCHECKED_CAST") override fun number(value: Number): T = if (algebra is NumericAlgebra<*>) diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt index f9996b61a..159c5d5ec 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt @@ -26,31 +26,31 @@ internal fun MST.compileWith(algebra: Algebra): Expression { } is MST.Numeric -> constant(node.value) - is MST.Unary -> call(algebra.unaryOperation(node.operation), visit(node.value)) + is MST.Unary -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) is MST.Binary -> when { algebra is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> constant( algebra.number( RealField - .binaryOperation(node.operation) + .binaryOperationFunction(node.operation) .invoke(node.left.value.toDouble(), node.right.value.toDouble()) ) ) algebra is NumericAlgebra && node.left is MST.Numeric -> call( - algebra.leftSideNumberOperation(node.operation), + algebra.leftSideNumberOperationFunction(node.operation), visit(node.left), visit(node.right), ) algebra is NumericAlgebra && node.right is MST.Numeric -> call( - algebra.rightSideNumberOperation(node.operation), + algebra.rightSideNumberOperationFunction(node.operation), visit(node.left), visit(node.right), ) else -> call( - algebra.binaryOperation(node.operation), + algebra.binaryOperationFunction(node.operation), visit(node.left), visit(node.right), ) diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt index 242a4154d..b9be02d49 100644 --- a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt +++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt @@ -13,8 +13,8 @@ internal class TestESTreeConsistencyWithInterpreter { @Test fun mstSpace() { val res1 = MstSpace.mstInSpace { - binaryOperation("+")( - unaryOperation("+")( + binaryOperationFunction("+")( + unaryOperationFunction("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( add(number(1), number(1)), 2 @@ -26,8 +26,8 @@ internal class TestESTreeConsistencyWithInterpreter { }("x" to MST.Numeric(2)) val res2 = MstSpace.mstInSpace { - binaryOperation("+")( - unaryOperation("+")( + binaryOperationFunction("+")( + unaryOperationFunction("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( add(number(1), number(1)), 2 @@ -44,8 +44,8 @@ internal class TestESTreeConsistencyWithInterpreter { @Test fun byteRing() { val res1 = ByteRing.mstInRing { - binaryOperation("+")( - unaryOperation("+")( + binaryOperationFunction("+")( + unaryOperationFunction("+")( (symbol("x") - (2.toByte() + (multiply( add(number(1), number(1)), 2 @@ -57,8 +57,8 @@ internal class TestESTreeConsistencyWithInterpreter { }("x" to 3.toByte()) val res2 = ByteRing.mstInRing { - binaryOperation("+")( - unaryOperation("+")( + binaryOperationFunction("+")( + unaryOperationFunction("+")( (symbol("x") - (2.toByte() + (multiply( add(number(1), number(1)), 2 @@ -74,7 +74,7 @@ internal class TestESTreeConsistencyWithInterpreter { @Test fun realField() { val res1 = RealField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one @@ -82,7 +82,7 @@ internal class TestESTreeConsistencyWithInterpreter { }("x" to 2.0) val res2 = RealField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one @@ -95,7 +95,7 @@ internal class TestESTreeConsistencyWithInterpreter { @Test fun complexField() { val res1 = ComplexField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one @@ -103,7 +103,7 @@ internal class TestESTreeConsistencyWithInterpreter { }("x" to 2.0.toComplex()) val res2 = ComplexField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt index 0821686fc..9d0d17e58 100644 --- a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt +++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt @@ -9,44 +9,44 @@ import kotlin.test.assertEquals internal class TestESTreeSpecialization { @Test fun testUnaryPlus() { - val expr = RealField.mstInField { unaryOperation("+")(symbol("x")) }.compile() + val expr = RealField.mstInField { unaryOperationFunction("+")(symbol("x")) }.compile() assertEquals(2.0, expr("x" to 2.0)) } @Test fun testUnaryMinus() { - val expr = RealField.mstInField { unaryOperation("-")(symbol("x")) }.compile() + val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile() assertEquals(-2.0, expr("x" to 2.0)) } @Test fun testAdd() { - val expr = RealField.mstInField { binaryOperation("+")(symbol("x"), symbol("x")) }.compile() + val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile() assertEquals(4.0, expr("x" to 2.0)) } @Test fun testSine() { - val expr = RealField.mstInField { unaryOperation("sin")(symbol("x")) }.compile() + val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile() assertEquals(0.0, expr("x" to 0.0)) } @Test fun testMinus() { - val expr = RealField.mstInField { binaryOperation("-")(symbol("x"), symbol("x")) }.compile() + val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile() assertEquals(0.0, expr("x" to 2.0)) } @Test fun testDivide() { - val expr = RealField.mstInField { binaryOperation("/")(symbol("x"), symbol("x")) }.compile() + val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile() assertEquals(1.0, expr("x" to 2.0)) } @Test fun testPower() { val expr = RealField - .mstInField { binaryOperation("pow")(symbol("x"), number(2)) } + .mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) } .compile() assertEquals(4.0, expr("x" to 2.0)) 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 932813182..b98c0bfce 100644 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt +++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt @@ -34,28 +34,28 @@ internal fun MST.compileWith(type: Class, algebra: Algebra): Exp } is MST.Numeric -> loadNumberConstant(node.value) - is MST.Unary -> buildCall(algebra.unaryOperation(node.operation)) { visit(node.value) } + is MST.Unary -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) } is MST.Binary -> when { algebra is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> loadObjectConstant( algebra.number( RealField - .binaryOperation(node.operation) + .binaryOperationFunction(node.operation) .invoke(node.left.value.toDouble(), node.right.value.toDouble()) ) ) - algebra is NumericAlgebra && node.left is MST.Numeric -> buildCall(algebra.leftSideNumberOperation(node.operation)) { + algebra is NumericAlgebra && node.left is MST.Numeric -> buildCall(algebra.leftSideNumberOperationFunction(node.operation)) { visit(node.left) visit(node.right) } - algebra is NumericAlgebra && node.right is MST.Numeric -> buildCall(algebra.rightSideNumberOperation(node.operation)) { + algebra is NumericAlgebra && node.right is MST.Numeric -> buildCall(algebra.rightSideNumberOperationFunction(node.operation)) { visit(node.left) visit(node.right) } - else -> buildCall(algebra.binaryOperation(node.operation)) { + else -> buildCall(algebra.binaryOperationFunction(node.operation)) { visit(node.left) visit(node.right) } diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt index 013ae789d..ae180bf3f 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt @@ -13,8 +13,8 @@ internal class TestAsmConsistencyWithInterpreter { @Test fun mstSpace() { val res1 = MstSpace.mstInSpace { - binaryOperation("+")( - unaryOperation("+")( + binaryOperationFunction("+")( + unaryOperationFunction("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( add(number(1), number(1)), 2 @@ -26,8 +26,8 @@ internal class TestAsmConsistencyWithInterpreter { }("x" to MST.Numeric(2)) val res2 = MstSpace.mstInSpace { - binaryOperation("+")( - unaryOperation("+")( + binaryOperationFunction("+")( + unaryOperationFunction("+")( number(3.toByte()) - (number(2.toByte()) + (multiply( add(number(1), number(1)), 2 @@ -44,8 +44,8 @@ internal class TestAsmConsistencyWithInterpreter { @Test fun byteRing() { val res1 = ByteRing.mstInRing { - binaryOperation("+")( - unaryOperation("+")( + binaryOperationFunction("+")( + unaryOperationFunction("+")( (symbol("x") - (2.toByte() + (multiply( add(number(1), number(1)), 2 @@ -57,8 +57,8 @@ internal class TestAsmConsistencyWithInterpreter { }("x" to 3.toByte()) val res2 = ByteRing.mstInRing { - binaryOperation("+")( - unaryOperation("+")( + binaryOperationFunction("+")( + unaryOperationFunction("+")( (symbol("x") - (2.toByte() + (multiply( add(number(1), number(1)), 2 @@ -74,7 +74,7 @@ internal class TestAsmConsistencyWithInterpreter { @Test fun realField() { val res1 = RealField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one @@ -82,7 +82,7 @@ internal class TestAsmConsistencyWithInterpreter { }("x" to 2.0) val res2 = RealField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one @@ -95,7 +95,7 @@ internal class TestAsmConsistencyWithInterpreter { @Test fun complexField() { val res1 = ComplexField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one @@ -103,7 +103,7 @@ internal class TestAsmConsistencyWithInterpreter { }("x" to 2.0.toComplex()) val res2 = ComplexField.mstInField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation("+")( + +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt index ce9e602d3..602c54651 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt @@ -9,44 +9,44 @@ import kotlin.test.assertEquals internal class TestAsmSpecialization { @Test fun testUnaryPlus() { - val expr = RealField.mstInField { unaryOperation("+")(symbol("x")) }.compile() + val expr = RealField.mstInField { unaryOperationFunction("+")(symbol("x")) }.compile() assertEquals(2.0, expr("x" to 2.0)) } @Test fun testUnaryMinus() { - val expr = RealField.mstInField { unaryOperation("-")(symbol("x")) }.compile() + val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile() assertEquals(-2.0, expr("x" to 2.0)) } @Test fun testAdd() { - val expr = RealField.mstInField { binaryOperation("+")(symbol("x"), symbol("x")) }.compile() + val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile() assertEquals(4.0, expr("x" to 2.0)) } @Test fun testSine() { - val expr = RealField.mstInField { unaryOperation("sin")(symbol("x")) }.compile() + val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile() assertEquals(0.0, expr("x" to 0.0)) } @Test fun testMinus() { - val expr = RealField.mstInField { binaryOperation("-")(symbol("x"), symbol("x")) }.compile() + val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile() assertEquals(0.0, expr("x" to 2.0)) } @Test fun testDivide() { - val expr = RealField.mstInField { binaryOperation("/")(symbol("x"), symbol("x")) }.compile() + val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile() assertEquals(1.0, expr("x" to 2.0)) } @Test fun testPower() { val expr = RealField - .mstInField { binaryOperation("pow")(symbol("x"), number(2)) } + .mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) } .compile() assertEquals(4.0, expr("x" to 2.0)) diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt index e2029ce19..3aa5392c8 100644 --- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt +++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt @@ -42,11 +42,11 @@ internal class ParserTest { val magicalAlgebra = object : Algebra { override fun symbol(value: String): String = value - override fun unaryOperation(operation: String): (arg: String) -> String { + override fun unaryOperationFunction(operation: String): (arg: String) -> String { throw NotImplementedError() } - override fun binaryOperation(operation: String): (left: String, right: String) -> String = + override fun binaryOperationFunction(operation: String): (left: String, right: String) -> String = when (operation) { "magic" -> { left, right -> "$left ★ $right" } else -> throw NotImplementedError() diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index e2413dea8..afbaf16e1 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -24,18 +24,18 @@ public abstract class FunctionalExpressionAlgebra>(public val /** * Builds an Expression of dynamic call of binary operation [operation] on [left] and [right]. */ - public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = { left, right -> Expression { arguments -> - algebra.binaryOperation(operation)(left.invoke(arguments), right.invoke(arguments)) + algebra.binaryOperationFunction(operation)(left.invoke(arguments), right.invoke(arguments)) } } /** * Builds an Expression of dynamic call of unary operation with name [operation] on [arg]. */ - public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = { arg -> - Expression { arguments -> algebra.unaryOperation(operation)(arg.invoke(arguments)) } + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> + Expression { arguments -> algebra.unaryOperationFunction(operation)(arg.invoke(arguments)) } } } @@ -50,7 +50,7 @@ public open class FunctionalExpressionSpace>(algebra: A) : * Builds an Expression of addition of two another expressions. */ public override fun add(a: Expression, b: Expression): Expression = - binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b) + binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b) /** * Builds an Expression of multiplication of expression by number. @@ -64,11 +64,11 @@ 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 - public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = - super.unaryOperation(operation) + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + super.unaryOperationFunction(operation) - public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = - super.binaryOperation(operation) + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + super.binaryOperationFunction(operation) } public open class FunctionalExpressionRing(algebra: A) : FunctionalExpressionSpace(algebra), @@ -80,16 +80,16 @@ public open class FunctionalExpressionRing(algebra: A) : FunctionalExpress * Builds an Expression of multiplication of two expressions. */ public override fun multiply(a: Expression, b: Expression): Expression = - binaryOperation(RingOperations.TIMES_OPERATION)(a, b) + binaryOperationFunction(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 - public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = - super.unaryOperation(operation) + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + super.unaryOperationFunction(operation) - public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = - super.binaryOperation(operation) + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + super.binaryOperationFunction(operation) } public open class FunctionalExpressionField(algebra: A) : @@ -99,49 +99,49 @@ public open class FunctionalExpressionField(algebra: A) : * Builds an Expression of division an expression by another one. */ public override fun divide(a: Expression, b: Expression): Expression = - binaryOperation(FieldOperations.DIV_OPERATION)(a, b) + binaryOperationFunction(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 - public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = - super.unaryOperation(operation) + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + super.unaryOperationFunction(operation) - public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = - super.binaryOperation(operation) + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + super.binaryOperationFunction(operation) } public open class FunctionalExpressionExtendedField(algebra: A) : FunctionalExpressionField(algebra), ExtendedField> where A : ExtendedField, A : NumericAlgebra { public override fun sin(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.SIN_OPERATION)(arg) + unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) public override fun cos(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.COS_OPERATION)(arg) + unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) public override fun asin(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.ASIN_OPERATION)(arg) + unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) public override fun acos(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.ACOS_OPERATION)(arg) + unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) public override fun atan(arg: Expression): Expression = - unaryOperation(TrigonometricOperations.ATAN_OPERATION)(arg) + unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) public override fun power(arg: Expression, pow: Number): Expression = - binaryOperation(PowerOperations.POW_OPERATION)(arg, number(pow)) + binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) public override fun exp(arg: Expression): Expression = - unaryOperation(ExponentialOperations.EXP_OPERATION)(arg) + unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - public override fun ln(arg: Expression): Expression = unaryOperation(ExponentialOperations.LN_OPERATION)(arg) + public override fun ln(arg: Expression): Expression = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - public override fun unaryOperation(operation: String): (arg: Expression) -> Expression = - super.unaryOperation(operation) + public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + super.unaryOperationFunction(operation) - public override fun binaryOperation(operation: String): (left: Expression, right: Expression) -> Expression = - super.binaryOperation(operation) + public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + super.binaryOperationFunction(operation) } public inline fun > A.expressionInSpace(block: FunctionalExpressionSpace.() -> Expression): Expression = diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt index 912c3f950..648af605c 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt @@ -19,10 +19,10 @@ public interface MatrixContext> : SpaceOperations T): M @Suppress("UNCHECKED_CAST") - public override fun binaryOperation(operation: String): (left: Matrix, right: Matrix) -> M = + public override fun binaryOperationFunction(operation: String): (left: Matrix, right: Matrix) -> M = when (operation) { "dot" -> { left, right -> left dot right } - else -> super.binaryOperation(operation) as (Matrix, Matrix) -> M + else -> super.binaryOperationFunction(operation) as (Matrix, Matrix) -> M } /** diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index d2cf8e0dd..24b417860 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -33,12 +33,12 @@ public interface Algebra { * * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 2. This function is symmetric with second `unaryOperation` overload: - * i.e. `unaryOperation(a)(b) == unaryOperation(a, b)`. + * i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. * * @param operation the name of operation. * @return an operation. */ - public fun unaryOperation(operation: String): (arg: T) -> T = + public fun unaryOperationFunction(operation: String): (arg: T) -> T = error("Unary operation $operation not defined in $this") /** @@ -47,14 +47,14 @@ public interface Algebra { * This function must follow two properties: * * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [unaryOperation] overload: - * i.e. `unaryOperation(a)(b) == unaryOperation(a, b)`. + * 2. This function is symmetric with second [unaryOperationFunction] overload: + * i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. * * @param operation the name of operation. * @param arg the argument of operation. * @return a result of operation. */ - public fun unaryOperation(operation: String, arg: T): T = unaryOperation(operation)(arg) + public fun unaryOperation(operation: String, arg: T): T = unaryOperationFunction(operation)(arg) /** * Dynamically dispatches a binary operation with the certain name. @@ -62,13 +62,13 @@ public interface Algebra { * This function must follow two properties: * * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [binaryOperation] overload: - * i.e. `binaryOperation(a)(b, c) == binaryOperation(a, b, c)`. + * 2. This function is symmetric with second [binaryOperationFunction] overload: + * i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * * @param operation the name of operation. * @return an operation. */ - public fun binaryOperation(operation: String): (left: T, right: T) -> T = + public fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = error("Binary operation $operation not defined in $this") /** @@ -77,15 +77,15 @@ public interface Algebra { * This function must follow two properties: * * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [binaryOperation] overload: - * i.e. `binaryOperation(a)(b, c) == binaryOperation(a, b, c)`. + * 2. This function is symmetric with second [binaryOperationFunction] overload: + * i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. * @param right the second argument of operation. * @return a result of operation. */ - public fun binaryOperation(operation: String, left: T, right: T): T = binaryOperation(operation)(left, right) + public fun binaryOperation(operation: String, left: T, right: T): T = binaryOperationFunction(operation)(left, right) } /** @@ -109,13 +109,13 @@ public interface NumericAlgebra : Algebra { * * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 2. This function is symmetric with the other [leftSideNumberOperation] overload: - * i.e. `leftSideNumberOperation(a)(b, c) == leftSideNumberOperation(a, b)`. + * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. * * @param operation the name of operation. * @return an operation. */ - public fun leftSideNumberOperation(operation: String): (left: Number, right: T) -> T = - { l, r -> binaryOperation(operation)(number(l), r) } + public fun leftSideNumberOperationFunction(operation: String): (left: Number, right: T) -> T = + { l, r -> binaryOperationFunction(operation)(number(l), r) } /** * Dynamically invokes a binary operation with the certain name with numeric first argument. @@ -124,7 +124,7 @@ public interface NumericAlgebra : Algebra { * * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. * 2. This function is symmetric with second [leftSideNumberOperation] overload: - * i.e. `leftSideNumberOperation(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -132,7 +132,7 @@ public interface NumericAlgebra : Algebra { * @return a result of operation. */ public fun leftSideNumberOperation(operation: String, left: Number, right: T): T = - leftSideNumberOperation(operation)(left, right) + leftSideNumberOperationFunction(operation)(left, right) /** * Dynamically dispatches a binary operation with the certain name with numeric first argument. @@ -140,14 +140,14 @@ public interface NumericAlgebra : Algebra { * This function must follow two properties: * * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [rightSideNumberOperation] overload: - * i.e. `rightSideNumberOperation(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: + * i.e. `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @return an operation. */ - public fun rightSideNumberOperation(operation: String): (left: T, right: Number) -> T = - { l, r -> binaryOperation(operation)(l, number(r)) } + public fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = + { l, r -> binaryOperationFunction(operation)(l, number(r)) } /** * Dynamically invokes a binary operation with the certain name with numeric second argument. @@ -155,8 +155,8 @@ public interface NumericAlgebra : Algebra { * This function must follow two properties: * * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [rightSideNumberOperation] overload: - * i.e. `rightSideNumberOperation(a)(b, c) == rightSideNumberOperation(a, b, c)`. + * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: + * i.e. `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -164,7 +164,7 @@ public interface NumericAlgebra : Algebra { * @return a result of operation. */ public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = - rightSideNumberOperation(operation)(left, right) + rightSideNumberOperationFunction(operation)(left, right) } /** @@ -261,16 +261,16 @@ public interface SpaceOperations : Algebra { */ public operator fun Number.times(b: T): T = b * this - public override fun unaryOperation(operation: String): (arg: T) -> T = when (operation) { + public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> arg } MINUS_OPERATION -> { arg -> -arg } - else -> super.unaryOperation(operation) + else -> super.unaryOperationFunction(operation) } - public override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { + public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { PLUS_OPERATION -> ::add MINUS_OPERATION -> { left, right -> left - right } - else -> super.binaryOperation(operation) + else -> super.binaryOperationFunction(operation) } public companion object { @@ -322,9 +322,9 @@ public interface RingOperations : SpaceOperations { */ public operator fun T.times(b: T): T = multiply(this, b) - public override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { + public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { TIMES_OPERATION -> ::multiply - else -> super.binaryOperation(operation) + else -> super.binaryOperationFunction(operation) } public companion object { @@ -409,9 +409,9 @@ public interface FieldOperations : RingOperations { */ public operator fun T.div(b: T): T = divide(this, b) - public override fun binaryOperation(operation: String): (left: T, right: T) -> T = when (operation) { + public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { DIV_OPERATION -> ::divide - else -> super.binaryOperation(operation) + else -> super.binaryOperationFunction(operation) } public companion object { diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt index 84d89b7eb..a7b73d5e0 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt @@ -14,7 +14,7 @@ public interface ExtendedFieldOperations : public override fun tan(arg: T): T = sin(arg) / cos(arg) public override fun tanh(arg: T): T = sinh(arg) / cosh(arg) - public override fun unaryOperation(operation: String): (arg: T) -> T = when (operation) { + public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { TrigonometricOperations.COS_OPERATION -> ::cos TrigonometricOperations.SIN_OPERATION -> ::sin TrigonometricOperations.TAN_OPERATION -> ::tan @@ -30,7 +30,7 @@ public interface ExtendedFieldOperations : PowerOperations.SQRT_OPERATION -> ::sqrt ExponentialOperations.EXP_OPERATION -> ::exp ExponentialOperations.LN_OPERATION -> ::ln - else -> super.unaryOperation(operation) + else -> super.unaryOperationFunction(operation) } } @@ -45,10 +45,10 @@ public interface ExtendedField : ExtendedFieldOperations, Field { public override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) public override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2 - public override fun rightSideNumberOperation(operation: String): (left: T, right: Number) -> T = + public override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = when (operation) { PowerOperations.POW_OPERATION -> ::power - else -> super.rightSideNumberOperation(operation) + else -> super.rightSideNumberOperationFunction(operation) } } @@ -80,10 +80,10 @@ public object RealField : ExtendedField, Norm { public override val one: Double get() = 1.0 - public override fun binaryOperation(operation: String): (left: Double, right: Double) -> Double = + public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { PowerOperations.POW_OPERATION -> ::power - else -> super.binaryOperation(operation) + else -> super.binaryOperationFunction(operation) } public override inline fun add(a: Double, b: Double): Double = a + b @@ -131,9 +131,9 @@ public object FloatField : ExtendedField, Norm { public override val one: Float get() = 1.0f - public override fun binaryOperation(operation: String): (left: Float, right: Float) -> Float = when (operation) { + public override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = when (operation) { PowerOperations.POW_OPERATION -> ::power - else -> super.binaryOperation(operation) + else -> super.binaryOperationFunction(operation) } public override inline fun add(a: Float, b: Float): Float = a + b From ea8dc63b1a327a5c773dbd33691cc48f61ee61b3 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 5 Jan 2021 20:14:50 +0700 Subject: [PATCH 39/55] Update doc comments in parser.kt --- .../src/jvmMain/kotlin/kscience/kmath/ast/parser.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 79cf77a6a..0b66e2c31 100644 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt +++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt @@ -1,3 +1,5 @@ +// TODO move to common when https://github.com/h0tk3y/better-parse/pull/33 is merged + package kscience.kmath.ast import com.github.h0tk3y.betterParse.combinators.* @@ -17,7 +19,8 @@ import kscience.kmath.operations.RingOperations import kscience.kmath.operations.SpaceOperations /** - * TODO move to common after IR version is released + * better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4. + * * @author Alexander Nozik and Iaroslav Postovalov */ public object ArithmeticsEvaluator : Grammar() { @@ -83,7 +86,7 @@ public object ArithmeticsEvaluator : Grammar() { } /** - * Tries to parse the string into [MST]. Returns [ParseResult] representing expression or error. + * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or error. * * @receiver the string to parse. * @return the [MST] node. @@ -91,7 +94,7 @@ public object ArithmeticsEvaluator : Grammar() { public fun String.tryParseMath(): ParseResult = ArithmeticsEvaluator.tryParseToEnd(this) /** - * Parses the string into [MST]. + * Parses the string into [MST] using [ArithmeticsEvaluator]. * * @receiver the string to parse. * @return the [MST] node. From fc152dec4fd514866ca37bef34a899e6bbea5e21 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 5 Jan 2021 20:15:50 +0700 Subject: [PATCH 40/55] Fix readme template --- docs/templates/ARTIFACT-TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templates/ARTIFACT-TEMPLATE.md b/docs/templates/ARTIFACT-TEMPLATE.md index c77948d4b..d46a431bd 100644 --- a/docs/templates/ARTIFACT-TEMPLATE.md +++ b/docs/templates/ARTIFACT-TEMPLATE.md @@ -14,7 +14,7 @@ > maven { url 'https://dl.bintray.com/mipt-npm/kscience' } > maven { url 'https://dl.bintray.com/mipt-npm/dev' } > maven { url 'https://dl.bintray.com/hotkeytlt/maven' } - +> > } > > dependencies { From 28ddc7cd959f4d524f3071e068f28591ab723db7 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 5 Jan 2021 20:16:42 +0700 Subject: [PATCH 41/55] Minor: regenerate readme files --- kmath-ast/README.md | 2 +- kmath-core/README.md | 2 +- kmath-for-real/README.md | 2 +- kmath-nd4j/README.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kmath-ast/README.md b/kmath-ast/README.md index bddc1c563..19e9ee4a9 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -26,7 +26,7 @@ This subproject implements the following features: > maven { url 'https://dl.bintray.com/mipt-npm/kscience' } > maven { url 'https://dl.bintray.com/mipt-npm/dev' } > maven { url 'https://dl.bintray.com/hotkeytlt/maven' } - +> > } > > dependencies { diff --git a/kmath-core/README.md b/kmath-core/README.md index 3a919e85a..7882e5252 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -26,7 +26,7 @@ The core features of KMath: > maven { url 'https://dl.bintray.com/mipt-npm/kscience' } > maven { url 'https://dl.bintray.com/mipt-npm/dev' } > maven { url 'https://dl.bintray.com/hotkeytlt/maven' } - +> > } > > dependencies { diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 2ddf78e57..d6b66b7da 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -21,7 +21,7 @@ > maven { url 'https://dl.bintray.com/mipt-npm/kscience' } > maven { url 'https://dl.bintray.com/mipt-npm/dev' } > maven { url 'https://dl.bintray.com/hotkeytlt/maven' } - +> > } > > dependencies { diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 176dfc09d..ff4ff4542 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -23,7 +23,7 @@ This subproject implements the following features: > maven { url 'https://dl.bintray.com/mipt-npm/kscience' } > maven { url 'https://dl.bintray.com/mipt-npm/dev' } > maven { url 'https://dl.bintray.com/hotkeytlt/maven' } - +> > } > > dependencies { From 06c551d3462724beb22c74a549862bd6f523dc96 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 5 Jan 2021 20:23:07 +0700 Subject: [PATCH 42/55] Update Gradle --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index be52383ef..4d9ca1649 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From b288704528ca54ace552369ca068cd1bf1983992 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 7 Jan 2021 18:07:00 +0300 Subject: [PATCH 43/55] Optimize RealMatrix dot operation --- ...iplicationBenchmark.kt => DotBenchmark.kt} | 24 ++++-- .../kmath/structures/typeSafeDimensions.kt | 5 +- .../kscience/kmath/commons/linear/CMMatrix.kt | 1 + .../kscience/kmath/linear/BufferMatrix.kt | 24 +----- .../kscience/kmath/linear/LUPDecomposition.kt | 11 +-- .../kscience/kmath/linear/MatrixContext.kt | 14 ++-- .../kmath/linear/RealMatrixContext.kt | 84 +++++++++++++++++++ .../kscience/kmath/dimensions/Wrappers.kt | 38 ++++----- .../kscience/dimensions/DMatrixContextTest.kt | 1 + .../kotlin/kscience/kmath/real/RealMatrix.kt | 11 +-- 10 files changed, 135 insertions(+), 78 deletions(-) rename examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/{MultiplicationBenchmark.kt => DotBenchmark.kt} (73%) create mode 100644 kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/MultiplicationBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt similarity index 73% rename from examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/MultiplicationBenchmark.kt rename to examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt index 9d2b02245..8823e86db 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/MultiplicationBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt @@ -2,19 +2,22 @@ package kscience.kmath.benchmarks import kotlinx.benchmark.Benchmark import kscience.kmath.commons.linear.CMMatrixContext -import kscience.kmath.commons.linear.CMMatrixContext.dot import kscience.kmath.commons.linear.toCM import kscience.kmath.ejml.EjmlMatrixContext import kscience.kmath.ejml.toEjml +import kscience.kmath.linear.BufferMatrixContext +import kscience.kmath.linear.RealMatrixContext import kscience.kmath.linear.real +import kscience.kmath.operations.RealField import kscience.kmath.operations.invoke +import kscience.kmath.structures.Buffer import kscience.kmath.structures.Matrix import org.openjdk.jmh.annotations.Scope import org.openjdk.jmh.annotations.State import kotlin.random.Random @State(Scope.Benchmark) -class MultiplicationBenchmark { +class DotBenchmark { companion object { val random = Random(12224) val dim = 1000 @@ -32,14 +35,14 @@ class MultiplicationBenchmark { @Benchmark fun commonsMathMultiplication() { - CMMatrixContext.invoke { + CMMatrixContext { cmMatrix1 dot cmMatrix2 } } @Benchmark fun ejmlMultiplication() { - EjmlMatrixContext.invoke { + EjmlMatrixContext { ejmlMatrix1 dot ejmlMatrix2 } } @@ -48,13 +51,22 @@ class MultiplicationBenchmark { fun ejmlMultiplicationwithConversion() { val ejmlMatrix1 = matrix1.toEjml() val ejmlMatrix2 = matrix2.toEjml() - EjmlMatrixContext.invoke { + EjmlMatrixContext { ejmlMatrix1 dot ejmlMatrix2 } } @Benchmark fun bufferedMultiplication() { - matrix1 dot matrix2 + BufferMatrixContext(RealField, Buffer.Companion::real).invoke{ + matrix1 dot matrix2 + } + } + + @Benchmark + fun realMultiplication(){ + RealMatrixContext { + matrix1 dot matrix2 + } } } \ No newline at end of file diff --git a/examples/src/main/kotlin/kscience/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/kscience/kmath/structures/typeSafeDimensions.kt index 987eea16f..96684f7dc 100644 --- a/examples/src/main/kotlin/kscience/kmath/structures/typeSafeDimensions.kt +++ b/examples/src/main/kotlin/kscience/kmath/structures/typeSafeDimensions.kt @@ -4,9 +4,8 @@ import kscience.kmath.dimensions.D2 import kscience.kmath.dimensions.D3 import kscience.kmath.dimensions.DMatrixContext import kscience.kmath.dimensions.Dimension -import kscience.kmath.operations.RealField -private fun DMatrixContext.simple() { +private fun DMatrixContext.simple() { val m1 = produce { i, j -> (i + j).toDouble() } val m2 = produce { i, j -> (i + j).toDouble() } @@ -18,7 +17,7 @@ private object D5 : Dimension { override val dim: UInt = 5u } -private fun DMatrixContext.custom() { +private fun DMatrixContext.custom() { val m1 = produce { i, j -> (i + j).toDouble() } val m2 = produce { i, j -> (i - j).toDouble() } val m3 = produce { i, j -> (i - j).toDouble() } diff --git a/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt index 712927400..49888f8d6 100644 --- a/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt +++ b/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt @@ -29,6 +29,7 @@ public class CMMatrix(public val origin: RealMatrix, features: Set.toCM(): CMMatrix = if (this is CMMatrix) { this } else { diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt index 8b50bbe33..402161207 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt @@ -1,8 +1,10 @@ package kscience.kmath.linear -import kscience.kmath.operations.RealField import kscience.kmath.operations.Ring -import kscience.kmath.structures.* +import kscience.kmath.structures.Buffer +import kscience.kmath.structures.BufferFactory +import kscience.kmath.structures.NDStructure +import kscience.kmath.structures.asSequence /** * Basic implementation of Matrix space based on [NDStructure] @@ -21,24 +23,6 @@ public class BufferMatrixContext>( public companion object } -@Suppress("OVERRIDE_BY_INLINE") -public object RealMatrixContext : GenericMatrixContext> { - public override val elementContext: RealField - get() = RealField - - public override inline fun produce( - rows: Int, - columns: Int, - initializer: (i: Int, j: Int) -> Double, - ): BufferMatrix { - val buffer = RealBuffer(rows * columns) { offset -> initializer(offset / columns, offset % columns) } - return BufferMatrix(rows, columns, buffer) - } - - public override inline fun point(size: Int, initializer: (Int) -> Double): Point = - RealBuffer(size, initializer) -} - public class BufferMatrix( public override val rowNum: Int, public override val colNum: Int, diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt index 099fa1909..bf2a9f59e 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt @@ -213,17 +213,8 @@ public inline fun , F : Field> GenericMatrixContext return decomposition.solveWithLUP(bufferFactory, b) } -public fun RealMatrixContext.solveWithLUP(a: Matrix, b: Matrix): FeaturedMatrix = - solveWithLUP(a, b) { it < 1e-11 } - public inline fun , F : Field> GenericMatrixContext>.inverseWithLUP( matrix: Matrix, noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, noinline checkSingular: (T) -> Boolean, -): FeaturedMatrix = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) - -/** - * Inverses a square matrix using LUP decomposition. Non square matrix will throw a error. - */ -public fun RealMatrixContext.inverseWithLUP(matrix: Matrix): FeaturedMatrix = - solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), Buffer.Companion::real) { it < 1e-11 } +): FeaturedMatrix = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt index d9dc57b0f..9bc79e12b 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt @@ -18,6 +18,11 @@ public interface MatrixContext> : SpaceOperations T): M + /** + * Produce a point compatible with matrix space (and possibly optimized for it) + */ + public fun point(size: Int, initializer: (Int) -> T): Point = Buffer.boxing(size, initializer) + @Suppress("UNCHECKED_CAST") public override fun binaryOperation(operation: String, left: Matrix, right: Matrix): M = when (operation) { "dot" -> left dot right @@ -61,10 +66,6 @@ public interface MatrixContext> : SpaceOperations): M = m * this public companion object { - /** - * Non-boxing double matrix - */ - public val real: RealMatrixContext = RealMatrixContext /** * A structured matrix with custom buffer @@ -88,11 +89,6 @@ public interface GenericMatrixContext, out M : Matrix> : */ public val elementContext: R - /** - * Produce a point compatible with matrix space - */ - public fun point(size: Int, initializer: (Int) -> T): Point - public override infix fun Matrix.dot(other: Matrix): M { //TODO add typed error require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt new file mode 100644 index 000000000..772b20f3b --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt @@ -0,0 +1,84 @@ +package kscience.kmath.linear + +import kscience.kmath.operations.RealField +import kscience.kmath.structures.Matrix +import kscience.kmath.structures.MutableBuffer +import kscience.kmath.structures.MutableBufferFactory +import kscience.kmath.structures.RealBuffer + +@Suppress("OVERRIDE_BY_INLINE") +public object RealMatrixContext : MatrixContext> { + + public override inline fun produce( + rows: Int, + columns: Int, + initializer: (i: Int, j: Int) -> Double, + ): BufferMatrix { + val buffer = RealBuffer(rows * columns) { offset -> initializer(offset / columns, offset % columns) } + return BufferMatrix(rows, columns, buffer) + } + + private fun Matrix.wrap(): BufferMatrix = if (this is BufferMatrix) this else { + produce(rowNum, colNum) { i, j -> get(i, j) } + } + + public fun one(rows: Int, columns: Int): FeaturedMatrix = VirtualMatrix(rows, columns, DiagonalFeature) { i, j -> + if (i == j) 1.0 else 0.0 + } + + public override infix fun Matrix.dot(other: Matrix): BufferMatrix { + require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } + return produce(rowNum, other.colNum) { i, j -> + var res = 0.0 + for (l in 0 until colNum) { + res += get(i, l) * other.get(l, j) + } + res + } + } + + public override infix fun Matrix.dot(vector: Point): Point { + require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } + return RealBuffer(rowNum) { i -> + var res = 0.0 + for (j in 0 until colNum) { + res += get(i, j) * vector[j] + } + res + } + } + + override fun add(a: Matrix, b: Matrix): BufferMatrix { + require(a.rowNum == b.rowNum) { "Row number mismatch in matrix addition. Left side: ${a.rowNum}, right side: ${b.rowNum}" } + require(a.colNum == b.colNum) { "Column number mismatch in matrix addition. Left side: ${a.colNum}, right side: ${b.colNum}" } + return produce(a.rowNum, a.colNum) { i, j -> + a[i, j] + b[i, j] + } + } + + override fun Matrix.times(value: Double): BufferMatrix = + produce(rowNum, colNum) { i, j -> get(i, j) * value } + + + override fun multiply(a: Matrix, k: Number): BufferMatrix = + produce(a.rowNum, a.colNum) { i, j -> a.get(i, j) * k.toDouble() } +} + + +/** + * Partially optimized real-valued matrix + */ +public val MatrixContext.Companion.real: RealMatrixContext get() = RealMatrixContext + +public fun RealMatrixContext.solveWithLUP(a: Matrix, b: Matrix): FeaturedMatrix { + // Use existing decomposition if it is provided by matrix + val bufferFactory: MutableBufferFactory = MutableBuffer.Companion::real + val decomposition = a.getFeature() ?: lup(bufferFactory, RealField, a) { it < 1e-11 } + return decomposition.solveWithLUP(bufferFactory, b) +} + +/** + * Inverses a square matrix using LUP decomposition. Non square matrix will throw a error. + */ +public fun RealMatrixContext.inverseWithLUP(matrix: Matrix): FeaturedMatrix = + solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum)) diff --git a/kmath-dimensions/src/commonMain/kotlin/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/kscience/kmath/dimensions/Wrappers.kt index 68a5dc262..0422d11b2 100644 --- a/kmath-dimensions/src/commonMain/kotlin/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/kscience/kmath/dimensions/Wrappers.kt @@ -1,11 +1,6 @@ package kscience.kmath.dimensions -import kscience.kmath.linear.GenericMatrixContext -import kscience.kmath.linear.MatrixContext -import kscience.kmath.linear.Point -import kscience.kmath.linear.transpose -import kscience.kmath.operations.RealField -import kscience.kmath.operations.Ring +import kscience.kmath.linear.* import kscience.kmath.operations.invoke import kscience.kmath.structures.Matrix import kscience.kmath.structures.Structure2D @@ -42,7 +37,7 @@ public interface DMatrix : Structure2D { * An inline wrapper for a Matrix */ public inline class DMatrixWrapper( - private val structure: Structure2D + private val structure: Structure2D, ) : DMatrix { override val shape: IntArray get() = structure.shape override operator fun get(i: Int, j: Int): T = structure[i, j] @@ -81,7 +76,7 @@ public inline class DPointWrapper(public val point: Point) /** * Basic operations on dimension-safe matrices. Operates on [Matrix] */ -public inline class DMatrixContext>(public val context: GenericMatrixContext>) { +public inline class DMatrixContext(public val context: MatrixContext>) { public inline fun Matrix.coerce(): DMatrix { require(rowNum == Dimension.dim().toInt()) { "Row number mismatch: expected ${Dimension.dim()} but found $rowNum" @@ -115,7 +110,7 @@ public inline class DMatrixContext>(public val context: Ge } public inline infix fun DMatrix.dot( - other: DMatrix + other: DMatrix, ): DMatrix = context { this@dot dot other }.coerce() public inline infix fun DMatrix.dot(vector: DPoint): DPoint = @@ -139,18 +134,19 @@ public inline class DMatrixContext>(public val context: Ge public inline fun DMatrix.transpose(): DMatrix = context { (this@transpose as Matrix).transpose() }.coerce() - /** - * A square unit matrix - */ - public inline fun one(): DMatrix = produce { i, j -> - if (i == j) context.elementContext.one else context.elementContext.zero - } - - public inline fun zero(): DMatrix = produce { _, _ -> - context.elementContext.zero - } - public companion object { - public val real: DMatrixContext = DMatrixContext(MatrixContext.real) + public val real: DMatrixContext = DMatrixContext(MatrixContext.real) } } + + +/** + * A square unit matrix + */ +public inline fun DMatrixContext.one(): DMatrix = produce { i, j -> + if (i == j) 1.0 else 0.0 +} + +public inline fun DMatrixContext.zero(): DMatrix = produce { _, _ -> + 0.0 +} \ No newline at end of file diff --git a/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt index f44b16753..5b330fcce 100644 --- a/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt +++ b/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt @@ -3,6 +3,7 @@ package kscience.dimensions import kscience.kmath.dimensions.D2 import kscience.kmath.dimensions.D3 import kscience.kmath.dimensions.DMatrixContext +import kscience.kmath.dimensions.one import kotlin.test.Test internal class DMatrixContextTest { diff --git a/kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt b/kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt index e8ad835e5..772abfbed 100644 --- a/kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt +++ b/kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt @@ -1,13 +1,7 @@ package kscience.kmath.real -import kscience.kmath.linear.FeaturedMatrix -import kscience.kmath.linear.MatrixContext -import kscience.kmath.linear.RealMatrixContext.elementContext -import kscience.kmath.linear.VirtualMatrix -import kscience.kmath.linear.inverseWithLUP +import kscience.kmath.linear.* import kscience.kmath.misc.UnstableKMathAPI -import kscience.kmath.operations.invoke -import kscience.kmath.operations.sum import kscience.kmath.structures.Buffer import kscience.kmath.structures.RealBuffer import kscience.kmath.structures.asIterable @@ -122,8 +116,7 @@ public fun RealMatrix.extractColumn(columnIndex: Int): RealMatrix = extractColumns(columnIndex..columnIndex) public fun RealMatrix.sumByColumn(): RealBuffer = RealBuffer(colNum) { j -> - val column = columns[j] - elementContext { sum(column.asIterable()) } + columns[j].asIterable().sum() } public fun RealMatrix.minByColumn(): RealBuffer = RealBuffer(colNum) { j -> From 2012d2c3f1a5a81e1a54fa98baef501c48f8321d Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Thu, 7 Jan 2021 22:40:30 +0700 Subject: [PATCH 44/55] Fix #172, add constant folding for unary operations from numeric nodes --- .../kotlin/kscience/kmath/ast/MST.kt | 24 +++++++------- .../kotlin/kscience/kmath/estree/estree.kt | 30 ++++++++++-------- .../jvmMain/kotlin/kscience/kmath/asm/asm.kt | 31 +++++++++++-------- .../kscience/kmath/asm/internal/AsmBuilder.kt | 2 +- 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt index 6cf746722..212fd0d0b 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt @@ -2,10 +2,9 @@ package kscience.kmath.ast import kscience.kmath.operations.Algebra import kscience.kmath.operations.NumericAlgebra -import kscience.kmath.operations.RealField /** - * A Mathematical Syntax Tree node for mathematical expressions. + * A Mathematical Syntax Tree (MST) node for mathematical expressions. * * @author Alexander Nozik */ @@ -57,21 +56,22 @@ public fun Algebra.evaluate(node: MST): T = when (node) { ?: error("Numeric nodes are not supported by $this") is MST.Symbolic -> symbol(node.value) - is MST.Unary -> unaryOperationFunction(node.operation)(evaluate(node.value)) + + is MST.Unary -> when { + this is NumericAlgebra && node.value is MST.Numeric -> unaryOperationFunction(node.operation)(number(node.value.value)) + else -> unaryOperationFunction(node.operation)(evaluate(node.value)) + } is MST.Binary -> when { - this !is NumericAlgebra -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right)) + this is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> + binaryOperationFunction(node.operation)(number(node.left.value), number(node.right.value)) - node.left is MST.Numeric && node.right is MST.Numeric -> { - val number = RealField - .binaryOperationFunction(node.operation) - .invoke(node.left.value.toDouble(), node.right.value.toDouble()) + this is NumericAlgebra && node.left is MST.Numeric -> + leftSideNumberOperationFunction(node.operation)(node.left.value, evaluate(node.right)) - number(number) - } + this is NumericAlgebra && node.right is MST.Numeric -> + rightSideNumberOperationFunction(node.operation)(evaluate(node.left), node.right.value) - node.left is MST.Numeric -> leftSideNumberOperationFunction(node.operation)(node.left.value, evaluate(node.right)) - node.right is MST.Numeric -> rightSideNumberOperationFunction(node.operation)(evaluate(node.left), node.right.value) else -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right)) } } diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt index 159c5d5ec..5c08ada31 100644 --- a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt @@ -1,18 +1,18 @@ package kscience.kmath.estree import kscience.kmath.ast.MST +import kscience.kmath.ast.MST.* import kscience.kmath.ast.MstExpression import kscience.kmath.estree.internal.ESTreeBuilder import kscience.kmath.estree.internal.estree.BaseExpression import kscience.kmath.expressions.Expression import kscience.kmath.operations.Algebra import kscience.kmath.operations.NumericAlgebra -import kscience.kmath.operations.RealField @PublishedApi internal fun MST.compileWith(algebra: Algebra): Expression { fun ESTreeBuilder.visit(node: MST): BaseExpression = when (node) { - is MST.Symbolic -> { + is Symbolic -> { val symbol = try { algebra.symbol(node.value) } catch (ignored: IllegalStateException) { @@ -25,25 +25,29 @@ internal fun MST.compileWith(algebra: Algebra): Expression { variable(node.value) } - is MST.Numeric -> constant(node.value) - is MST.Unary -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) + is Numeric -> constant(node.value) - is MST.Binary -> when { - algebra is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> constant( - algebra.number( - RealField - .binaryOperationFunction(node.operation) - .invoke(node.left.value.toDouble(), node.right.value.toDouble()) - ) + is Unary -> when { + algebra is NumericAlgebra && node.value is Numeric -> constant( + algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value))) + + else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) + } + + is Binary -> when { + algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant( + algebra + .binaryOperationFunction(node.operation) + .invoke(algebra.number(node.left.value), algebra.number(node.right.value)) ) - algebra is NumericAlgebra && node.left is MST.Numeric -> call( + algebra is NumericAlgebra && node.left is Numeric -> call( algebra.leftSideNumberOperationFunction(node.operation), visit(node.left), visit(node.right), ) - algebra is NumericAlgebra && node.right is MST.Numeric -> call( + algebra is NumericAlgebra && node.right is Numeric -> call( algebra.rightSideNumberOperationFunction(node.operation), visit(node.left), visit(node.right), 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 b98c0bfce..55cdec243 100644 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt +++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt @@ -3,11 +3,11 @@ package kscience.kmath.asm import kscience.kmath.asm.internal.AsmBuilder import kscience.kmath.asm.internal.buildName import kscience.kmath.ast.MST +import kscience.kmath.ast.MST.* import kscience.kmath.ast.MstExpression import kscience.kmath.expressions.Expression import kscience.kmath.operations.Algebra import kscience.kmath.operations.NumericAlgebra -import kscience.kmath.operations.RealField /** * Compiles given MST to an Expression using AST compiler. @@ -20,7 +20,7 @@ import kscience.kmath.operations.RealField @PublishedApi internal fun MST.compileWith(type: Class, algebra: Algebra): Expression { fun AsmBuilder.visit(node: MST): Unit = when (node) { - is MST.Symbolic -> { + is Symbolic -> { val symbol = try { algebra.symbol(node.value) } catch (ignored: IllegalStateException) { @@ -33,24 +33,29 @@ internal fun MST.compileWith(type: Class, algebra: Algebra): Exp loadVariable(node.value) } - is MST.Numeric -> loadNumberConstant(node.value) - is MST.Unary -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) } + is Numeric -> loadNumberConstant(node.value) - is MST.Binary -> when { - algebra is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> loadObjectConstant( - algebra.number( - RealField - .binaryOperationFunction(node.operation) - .invoke(node.left.value.toDouble(), node.right.value.toDouble()) - ) + is Unary -> when { + algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant( + algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value))) + + else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) } + } + + is Binary -> when { + algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant( + algebra.binaryOperationFunction(node.operation) + .invoke(algebra.number(node.left.value), algebra.number(node.right.value)) ) - algebra is NumericAlgebra && node.left is MST.Numeric -> buildCall(algebra.leftSideNumberOperationFunction(node.operation)) { + algebra is NumericAlgebra && node.left is Numeric -> buildCall( + algebra.leftSideNumberOperationFunction(node.operation)) { visit(node.left) visit(node.right) } - algebra is NumericAlgebra && node.right is MST.Numeric -> buildCall(algebra.rightSideNumberOperationFunction(node.operation)) { + algebra is NumericAlgebra && node.right is Numeric -> buildCall( + algebra.rightSideNumberOperationFunction(node.operation)) { visit(node.left) visit(node.right) } 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 1edbed28d..93d8d1143 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 @@ -191,7 +191,7 @@ internal class AsmBuilder( } val cls = classLoader.defineClass(className, classWriter.toByteArray()) - java.io.File("dump.class").writeBytes(classWriter.toByteArray()) + // java.io.File("dump.class").writeBytes(classWriter.toByteArray()) val l = MethodHandles.publicLookup() if (hasConstants) From 0ef7e7ca52ab6bedc1f33f6b5e2e1572c61b83f6 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sun, 10 Jan 2021 17:53:15 +0700 Subject: [PATCH 45/55] Update Gradle again --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4d9ca1649..da9702f9e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 7fdd001a77e14aa745d629d528971b979a2f019a Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Sat, 16 Jan 2021 15:51:36 +0700 Subject: [PATCH 46/55] Update KDoc comments for Matrix classes, improve MatrixFeature API, implement new features with EJML matrix, delete inversion API from EJML in favor of InverseMatrixFeature, override point by EJML matrix --- .../kscience/kmath/linear/FeaturedMatrix.kt | 10 +- .../kscience/kmath/linear/LUPDecomposition.kt | 14 ++- .../kscience/kmath/linear/MatrixFeatures.kt | 114 ++++++++++++++++-- .../kscience/kmath/structures/Structure2D.kt | 45 +++++-- .../kotlin/kscience/kmath/ejml/EjmlMatrix.kt | 83 ++++++++----- .../kscience/kmath/ejml/EjmlMatrixContext.kt | 15 +-- .../kscience/kmath/ejml/EjmlMatrixTest.kt | 4 +- 7 files changed, 217 insertions(+), 68 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/FeaturedMatrix.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/FeaturedMatrix.kt index 68272203c..119f5d844 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/FeaturedMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/FeaturedMatrix.kt @@ -7,10 +7,16 @@ import kscience.kmath.structures.asBuffer import kotlin.math.sqrt /** - * A 2d structure plus optional matrix-specific features + * A [Matrix] that holds [MatrixFeature] objects. + * + * @param T the type of items. */ public interface FeaturedMatrix : Matrix { - override val shape: IntArray get() = intArrayOf(rowNum, colNum) + public override val shape: IntArray get() = intArrayOf(rowNum, colNum) + + /** + * The set of features this matrix possesses. + */ public val features: Set /** diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt index bf2a9f59e..75acaf8a1 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt @@ -4,16 +4,15 @@ import kscience.kmath.operations.* import kscience.kmath.structures.* /** - * Common implementation of [LUPDecompositionFeature] + * Common implementation of [LupDecompositionFeature]. */ public class LUPDecomposition( public val context: MatrixContext>, public val elementContext: Field, - public val lu: Structure2D, + public val lu: Matrix, public val pivot: IntArray, private val even: Boolean, -) : LUPDecompositionFeature, DeterminantFeature { - +) : LupDecompositionFeature, DeterminantFeature { /** * Returns the matrix L of the decomposition. * @@ -151,7 +150,10 @@ public inline fun , F : Field> GenericMatrixContext public fun MatrixContext>.lup(matrix: Matrix): LUPDecomposition = lup(Buffer.Companion::real, RealField, matrix) { it < 1e-11 } -public fun LUPDecomposition.solveWithLUP(factory: MutableBufferFactory, matrix: Matrix): FeaturedMatrix { +public fun LUPDecomposition.solveWithLUP( + factory: MutableBufferFactory, + matrix: Matrix +): FeaturedMatrix { require(matrix.rowNum == pivot.size) { "Matrix dimension mismatch. Expected ${pivot.size}, but got ${matrix.colNum}" } BufferAccessor2D(matrix.rowNum, matrix.colNum, factory).run { @@ -217,4 +219,4 @@ public inline fun , F : Field> GenericMatrixContext matrix: Matrix, noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, noinline checkSingular: (T) -> Boolean, -): FeaturedMatrix = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) \ No newline at end of file +): FeaturedMatrix = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt index a82032e50..767b58eba 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt @@ -1,62 +1,154 @@ package kscience.kmath.linear /** - * A marker interface representing some matrix feature like diagonal, sparse, zero, etc. Features used to optimize matrix - * operations performance in some cases. + * A marker interface representing some properties of matrices or additional transformations of them. Features are used + * to optimize matrix operations performance in some cases or retrieve the APIs. */ public interface MatrixFeature /** - * The matrix with this feature is considered to have only diagonal non-null elements + * Matrices with this feature are considered to have only diagonal non-null elements. */ public object DiagonalFeature : MatrixFeature /** - * Matrix with this feature has all zero elements + * Matrices with this feature have all zero elements. */ public object ZeroFeature : MatrixFeature /** - * Matrix with this feature have unit elements on diagonal and zero elements in all other places + * Matrices with this feature have unit elements on diagonal and zero elements in all other places. */ public object UnitFeature : MatrixFeature /** - * Inverted matrix feature + * Matrices with this feature can be inverted: [inverse] = `a`-1 where `a` is the owning matrix. + * + * @param T the type of matrices' items. */ public interface InverseMatrixFeature : MatrixFeature { + /** + * The inverse matrix of the matrix that owns this feature. + */ public val inverse: FeaturedMatrix } /** - * A determinant container + * Matrices with this feature can compute their determinant. */ public interface DeterminantFeature : MatrixFeature { + /** + * The determinant of the matrix that owns this feature. + */ public val determinant: T } +/** + * Produces a [DeterminantFeature] where the [DeterminantFeature.determinant] is [determinant]. + * + * @param determinant the value of determinant. + * @return a new [DeterminantFeature]. + */ @Suppress("FunctionName") public fun DeterminantFeature(determinant: T): DeterminantFeature = object : DeterminantFeature { override val determinant: T = determinant } /** - * Lower triangular matrix + * Matrices with this feature are lower triangular ones. */ public object LFeature : MatrixFeature /** - * Upper triangular feature + * Matrices with this feature are upper triangular ones. */ public object UFeature : MatrixFeature /** - * TODO add documentation + * Matrices with this feature support LU factorization with partial pivoting: *[p] · a = [l] · [u]* where + * *a* is the owning matrix. + * + * @param T the type of matrices' items. */ -public interface LUPDecompositionFeature : MatrixFeature { +public interface LupDecompositionFeature : MatrixFeature { + /** + * The lower triangular matrix in this decomposition. It may have [LFeature]. + */ public val l: FeaturedMatrix + + /** + * The upper triangular matrix in this decomposition. It may have [UFeature]. + */ public val u: FeaturedMatrix + + /** + * The permutation matrix in this decomposition. + */ public val p: FeaturedMatrix } +/** + * Matrices with this feature are orthogonal ones: *a · aT = u* where *a* is the owning matrix, *u* + * is the unit matrix ([UnitFeature]). + */ +public object OrthogonalFeature : MatrixFeature + +/** + * Matrices with this feature support QR factorization: *a = [q] · [r]* where *a* is the owning matrix. + * + * @param T the type of matrices' items. + */ +public interface QRDecompositionFeature : MatrixFeature { + /** + * The orthogonal matrix in this decomposition. It may have [OrthogonalFeature]. + */ + public val q: FeaturedMatrix + + /** + * The upper triangular matrix in this decomposition. It may have [UFeature]. + */ + public val r: FeaturedMatrix +} + +/** + * Matrices with this feature support Cholesky factorization: *a = [l] · [l]H* where *a* is the + * owning matrix. + * + * @param T the type of matrices' items. + */ +public interface CholeskyDecompositionFeature : MatrixFeature { + /** + * The triangular matrix in this decomposition. It may have either [UFeature] or [LFeature]. + */ + public val l: FeaturedMatrix +} + +/** + * Matrices with this feature support SVD: *a = [u] · [s] · [v]H* where *a* is the owning + * matrix. + * + * @param T the type of matrices' items. + */ +public interface SingularValueDecompositionFeature : MatrixFeature { + /** + * The matrix in this decomposition. It is unitary, and it consists from left singular vectors. + */ + public val u: FeaturedMatrix + + /** + * The matrix in this decomposition. Its main diagonal elements are singular values. + */ + public val s: FeaturedMatrix + + /** + * The matrix in this decomposition. It is unitary, and it consists from right singular vectors. + */ + public val v: FeaturedMatrix + + /** + * The buffer of singular values of this SVD. + */ + public val singularValues: Point +} + //TODO add sparse matrix feature diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Structure2D.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Structure2D.kt index 25fdf3f3d..bac7d3389 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Structure2D.kt @@ -1,12 +1,40 @@ package kscience.kmath.structures /** - * A structure that is guaranteed to be two-dimensional + * A structure that is guaranteed to be two-dimensional. + * + * @param T the type of items. */ public interface Structure2D : NDStructure { + /** + * The number of rows in this structure. + */ public val rowNum: Int get() = shape[0] + + /** + * The number of columns in this structure. + */ public val colNum: Int get() = shape[1] + /** + * The buffer of rows of this structure. It gets elements from the structure dynamically. + */ + public val rows: Buffer> + get() = VirtualBuffer(rowNum) { i -> VirtualBuffer(colNum) { j -> get(i, j) } } + + /** + * The buffer of columns of this structure. It gets elements from the structure dynamically. + */ + public val columns: Buffer> + get() = VirtualBuffer(colNum) { j -> VirtualBuffer(rowNum) { i -> get(i, j) } } + + /** + * Retrieves an element from the structure by two indices. + * + * @param i the first index. + * @param j the second index. + * @return an element. + */ public operator fun get(i: Int, j: Int): T override operator fun get(index: IntArray): T { @@ -14,15 +42,9 @@ public interface Structure2D : NDStructure { return get(index[0], index[1]) } - public val rows: Buffer> - get() = VirtualBuffer(rowNum) { i -> VirtualBuffer(colNum) { j -> get(i, j) } } - - public val columns: Buffer> - 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 @@ -47,4 +69,9 @@ public fun NDStructure.as2D(): Structure2D = if (shape.size == 2) else error("Can't create 2d-structure from ${shape.size}d-structure") +/** + * Alias for [Structure2D] with more familiar name. + * + * @param T the type of items. + */ public typealias Matrix = Structure2D diff --git a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt index ed6b1571e..5b7d0a01b 100644 --- a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt +++ b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt @@ -1,12 +1,10 @@ package kscience.kmath.ejml +import kscience.kmath.linear.* +import kscience.kmath.structures.NDStructure +import kscience.kmath.structures.RealBuffer import org.ejml.dense.row.factory.DecompositionFactory_DDRM import org.ejml.simple.SimpleMatrix -import kscience.kmath.linear.DeterminantFeature -import kscience.kmath.linear.FeaturedMatrix -import kscience.kmath.linear.LUPDecompositionFeature -import kscience.kmath.linear.MatrixFeature -import kscience.kmath.structures.NDStructure /** * Represents featured matrix over EJML [SimpleMatrix]. @@ -14,42 +12,71 @@ import kscience.kmath.structures.NDStructure * @property origin the underlying [SimpleMatrix]. * @author Iaroslav Postovalov */ -public class EjmlMatrix(public val origin: SimpleMatrix, features: Set? = null) : FeaturedMatrix { +public class EjmlMatrix(public val origin: SimpleMatrix, features: Set = emptySet()) : + FeaturedMatrix { public override val rowNum: Int get() = origin.numRows() public override val colNum: Int get() = origin.numCols() - public override val shape: IntArray - get() = intArrayOf(origin.numRows(), origin.numCols()) + public override val shape: IntArray by lazy { intArrayOf(rowNum, colNum) } - public override val features: Set = setOf( - object : LUPDecompositionFeature, DeterminantFeature { - override val determinant: Double - get() = origin.determinant() + public override val features: Set = hashSetOf( + object : InverseMatrixFeature { + override val inverse: FeaturedMatrix by lazy { EjmlMatrix(origin.invert()) } + }, - private val lup by lazy { - val ludecompositionF64 = DecompositionFactory_DDRM.lu(origin.numRows(), origin.numCols()) - .also { it.decompose(origin.ddrm.copy()) } + object : DeterminantFeature { + override val determinant: Double by lazy(origin::determinant) + }, - Triple( - EjmlMatrix(SimpleMatrix(ludecompositionF64.getRowPivot(null))), - EjmlMatrix(SimpleMatrix(ludecompositionF64.getLower(null))), - EjmlMatrix(SimpleMatrix(ludecompositionF64.getUpper(null))), - ) + object : SingularValueDecompositionFeature { + private val svd by lazy { + DecompositionFactory_DDRM.svd(origin.numRows(), origin.numCols(), true, true, false) + .apply { decompose(origin.ddrm.copy()) } } - override val l: FeaturedMatrix - get() = lup.second + override val u: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(svd.getU(null, false))) } + override val s: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(svd.getW(null))) } + override val v: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(svd.getV(null, false))) } + override val singularValues: Point by lazy { RealBuffer(svd.singularValues) } + }, - override val u: FeaturedMatrix - get() = lup.third + object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_DDRM.qr().apply { decompose(origin.ddrm.copy()) } + } - override val p: FeaturedMatrix - get() = lup.first - } - ) union features.orEmpty() + override val q: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(qr.getQ(null, false))) } + override val r: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(qr.getR(null, false))) } + }, + + object : CholeskyDecompositionFeature { + override val l: FeaturedMatrix by lazy { + val cholesky = + DecompositionFactory_DDRM.chol(rowNum, true).apply { decompose(origin.ddrm.copy()) } + + EjmlMatrix(SimpleMatrix(cholesky.getT(null)), setOf(LFeature)) + } + }, + + object : LupDecompositionFeature { + private val lup by lazy { + DecompositionFactory_DDRM.lu(origin.numRows(), origin.numCols()).apply { decompose(origin.ddrm.copy()) } + } + + override val l: FeaturedMatrix by lazy { + EjmlMatrix(SimpleMatrix(lup.getLower(null)), setOf(LFeature)) + } + + override val u: FeaturedMatrix by lazy { + EjmlMatrix(SimpleMatrix(lup.getUpper(null)), setOf(UFeature)) + } + + override val p: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(lup.getRowPivot(null))) } + }, + ) union features public override fun suggestFeature(vararg features: MatrixFeature): EjmlMatrix = EjmlMatrix(origin, this.features + features) diff --git a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt index 31792e39c..f8791b72c 100644 --- a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt +++ b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt @@ -17,7 +17,6 @@ public fun Matrix.toEjml(): EjmlMatrix = * @author Iaroslav Postovalov */ public object EjmlMatrixContext : MatrixContext { - /** * Converts this vector to EJML one. */ @@ -33,6 +32,11 @@ public object EjmlMatrixContext : MatrixContext { } }) + override fun point(size: Int, initializer: (Int) -> Double): Point = + EjmlVector(SimpleMatrix(size, 1).also { + (0 until it.numRows()).forEach { row -> it[row, 0] = initializer(row) } + }) + public override fun Matrix.dot(other: Matrix): EjmlMatrix = EjmlMatrix(toEjml().origin.mult(other.toEjml().origin)) @@ -73,12 +77,3 @@ public fun EjmlMatrixContext.solve(a: Matrix, b: Matrix): EjmlMa */ public fun EjmlMatrixContext.solve(a: Matrix, b: Point): EjmlVector = EjmlVector(a.toEjml().origin.solve(b.toEjml().origin)) - -/** - * Returns the inverse of given matrix: b = a^(-1). - * - * @param a the matrix. - * @return the inverse of this matrix. - * @author Iaroslav Postovalov - */ -public fun EjmlMatrixContext.inverse(a: Matrix): EjmlMatrix = EjmlMatrix(a.toEjml().origin.invert()) diff --git a/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt index e0f15be83..70b82a3cb 100644 --- a/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt +++ b/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt @@ -1,7 +1,7 @@ package kscience.kmath.ejml import kscience.kmath.linear.DeterminantFeature -import kscience.kmath.linear.LUPDecompositionFeature +import kscience.kmath.linear.LupDecompositionFeature import kscience.kmath.linear.MatrixFeature import kscience.kmath.linear.getFeature import org.ejml.dense.row.factory.DecompositionFactory_DDRM @@ -44,7 +44,7 @@ internal class EjmlMatrixTest { val w = EjmlMatrix(m) val det = w.getFeature>() ?: fail() assertEquals(m.determinant(), det.determinant) - val lup = w.getFeature>() ?: fail() + val lup = w.getFeature>() ?: fail() val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows(), m.numCols()) .also { it.decompose(m.ddrm.copy()) } From 4635080317826427189bec6802e18922b60972eb Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 18 Jan 2021 21:33:53 +0300 Subject: [PATCH 47/55] Optimize RealMatrix dot operation --- examples/src/main/kotlin/kscience/kmath/structures/NDField.kt | 4 ++-- .../kotlin/kscience/kmath/linear/RealMatrixContext.kt | 2 +- .../kotlin/kscience/kmath/structures/NDStructure.kt | 4 ++++ settings.gradle.kts | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt index e53af0dee..778d811fd 100644 --- a/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt @@ -45,14 +45,14 @@ fun main() { measureAndPrint("Specialized addition") { specializedField { var res: NDBuffer = one - repeat(n) { res += 1.0 } + repeat(n) { res += one } } } measureAndPrint("Nd4j specialized addition") { nd4jField { var res = one - repeat(n) { res += 1.0 as Number } + repeat(n) { res += one } } } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt index 772b20f3b..90e251c3a 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt @@ -61,7 +61,7 @@ public object RealMatrixContext : MatrixContext> { override fun multiply(a: Matrix, k: Number): BufferMatrix = - produce(a.rowNum, a.colNum) { i, j -> a.get(i, j) * k.toDouble() } + produce(a.rowNum, a.colNum) { i, j -> a[i, j] * k.toDouble() } } 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 08160adf4..5c5d28882 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt @@ -38,6 +38,7 @@ public interface NDStructure { */ public fun elements(): Sequence> + //force override equality and hash code public override fun equals(other: Any?): Boolean public override fun hashCode(): Int @@ -133,6 +134,9 @@ public interface MutableNDStructure : NDStructure { public operator fun set(index: IntArray, value: T) } +/** + * Transform a structure element-by element in place. + */ public inline fun MutableNDStructure.mapInPlace(action: (IntArray, T) -> T): Unit = elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } diff --git a/settings.gradle.kts b/settings.gradle.kts index da33fea59..025e4a3c6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,7 +8,7 @@ pluginManagement { maven("https://dl.bintray.com/kotlin/kotlinx") } - val toolsVersion = "0.7.1" + val toolsVersion = "0.7.2-dev-2" val kotlinVersion = "1.4.21" plugins { From ad822271b3f552ff2e57d44031e9bb1fb4f00dc0 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 19 Jan 2021 20:25:26 +0700 Subject: [PATCH 48/55] Update changelog --- CHANGELOG.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e542d210c..0a2ae4109 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,27 +4,28 @@ ### Added - `fun` annotation for SAM interfaces in library - Explicit `public` visibility for all public APIs -- Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140). +- Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140) - Automatic README generation for features (#139) - Native support for `memory`, `core` and `dimensions` -- `kmath-ejml` to supply EJML SimpleMatrix wrapper (https://github.com/mipt-npm/kmath/pull/136). +- `kmath-ejml` to supply EJML SimpleMatrix wrapper (https://github.com/mipt-npm/kmath/pull/136) - A separate `Symbol` entity, which is used for global unbound symbol. - A `Symbol` indexing scope. - Basic optimization API for Commons-math. - Chi squared optimization for array-like data in CM - `Fitting` utility object in prob/stat -- ND4J support module submitting `NDStructure` and `NDAlgebra` over `INDArray`. -- Coroutine-deterministic Monte-Carlo scope with a random number generator. -- Some minor utilities to `kmath-for-real`. +- ND4J support module submitting `NDStructure` and `NDAlgebra` over `INDArray` +- Coroutine-deterministic Monte-Carlo scope with a random number generator +- Some minor utilities to `kmath-for-real` - Generic operation result parameter to `MatrixContext` +- New `MatrixFeature` interfaces for matrix decompositions ### Changed -- Package changed from `scientifik` to `kscience.kmath`. -- Gradle version: 6.6 -> 6.7.1 +- Package changed from `scientifik` to `kscience.kmath` +- Gradle version: 6.6 -> 6.8 - Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`) -- `Polynomial` secondary constructor made function. -- Kotlin version: 1.3.72 -> 1.4.20 -- `kmath-ast` doesn't depend on heavy `kotlin-reflect` library. +- `Polynomial` secondary constructor made function +- Kotlin version: 1.3.72 -> 1.4.21 +- `kmath-ast` doesn't depend on heavy `kotlin-reflect` library - Full autodiff refactoring based on `Symbol` - `kmath-prob` renamed to `kmath-stat` - Grid generators moved to `kmath-for-real` From ab32cd95616adfb409c28cc0fb13754f69031081 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 19 Jan 2021 17:16:43 +0300 Subject: [PATCH 49/55] Numeric operations are decoupled from Ring --- CHANGELOG.md | 1 + build.gradle.kts | 2 +- .../kmath/benchmarks/LargeNDBenchmark.kt | 25 ++++ .../kmath/stat/DistributionBenchmark.kt | 3 +- .../kscience/kmath/structures/ComplexND.kt | 2 +- .../kscience/kmath/structures/NDField.kt | 8 +- .../kotlin/kscience/kmath/ast/MstAlgebra.kt | 31 +++-- .../DerivativeStructureExpression.kt | 7 +- .../FunctionalExpressionAlgebra.kt | 32 +++-- .../kmath/expressions/SimpleAutoDiff.kt | 4 +- .../kscience/kmath/linear/MatrixFeatures.kt | 4 +- .../kscience/kmath/operations/Algebra.kt | 117 +--------------- .../kscience/kmath/operations/BigInt.kt | 4 +- .../kscience/kmath/operations/Complex.kt | 4 +- .../kmath/operations/NumericAlgebra.kt | 125 ++++++++++++++++++ .../{NumberAlgebra.kt => numbers.kt} | 15 ++- .../kmath/structures/ComplexNDField.kt | 23 ++-- .../kmath/structures/RealBufferField.kt | 2 + .../kscience/kmath/structures/RealNDField.kt | 16 ++- .../kscience/kmath/structures/NDFieldTest.kt | 3 +- .../kscience/kmath/operations/BigNumbers.kt | 8 +- .../kotlin/kscience/kmath/ejml/EjmlMatrix.kt | 14 +- .../kscience/kmath/ejml/EjmlMatrixContext.kt | 6 + .../kscience.kmath.nd4j/Nd4jArrayAlgebra.kt | 46 ++++--- settings.gradle.kts | 4 +- 25 files changed, 300 insertions(+), 206 deletions(-) create mode 100644 examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt create mode 100644 kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumericAlgebra.kt rename kmath-core/src/commonMain/kotlin/kscience/kmath/operations/{NumberAlgebra.kt => numbers.kt} (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index e542d210c..840733d92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - Optimized dot product for buffer matrices moved to `kmath-for-real` - EjmlMatrix context is an object - Matrix LUP `inverse` renamed to `inverseWithLUP` +- `NumericAlgebra` moved outside of regular algebra chain (`Ring` no longer implements it). ### Deprecated diff --git a/build.gradle.kts b/build.gradle.kts index 90a39c531..d171bd608 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { id("ru.mipt.npm.project") } -internal val kmathVersion: String by extra("0.2.0-dev-4") +internal val kmathVersion: String by extra("0.2.0-dev-5") internal val bintrayRepo: String by extra("kscience") internal val githubProject: String by extra("kmath") diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt new file mode 100644 index 000000000..395fde619 --- /dev/null +++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt @@ -0,0 +1,25 @@ +package kscience.kmath.benchmarks + +import kscience.kmath.structures.NDField +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State +import org.openjdk.jmh.infra.Blackhole +import kotlin.random.Random + +@State(Scope.Benchmark) +class LargeNDBenchmark { + val arraySize = 10000 + val RANDOM = Random(222) + val src1 = DoubleArray(arraySize) { RANDOM.nextDouble() } + val src2 = DoubleArray(arraySize) { RANDOM.nextDouble() } + val field = NDField.real(arraySize) + val kmathArray1 = field.produce { (a) -> src1[a] } + val kmathArray2 = field.produce { (a) -> src2[a] } + + @Benchmark + fun test10000(bh: Blackhole) { + bh.consume(field.add(kmathArray1, kmathArray2)) + } + +} \ No newline at end of file diff --git a/examples/src/main/kotlin/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/kscience/kmath/stat/DistributionBenchmark.kt index ef554aeff..99d3cd504 100644 --- a/examples/src/main/kotlin/kscience/kmath/stat/DistributionBenchmark.kt +++ b/examples/src/main/kotlin/kscience/kmath/stat/DistributionBenchmark.kt @@ -3,7 +3,6 @@ package kscience.kmath.commons.prob import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking -import kscience.kmath.chains.BlockingRealChain import kscience.kmath.stat.* import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler import org.apache.commons.rng.simple.RandomSource @@ -13,7 +12,7 @@ import java.time.Instant private fun runChain(): Duration { val generator = RandomGenerator.fromSource(RandomSource.MT, 123L) val normal = Distribution.normal(NormalSamplerMethod.Ziggurat) - val chain = normal.sample(generator) as BlockingRealChain + val chain = normal.sample(generator) val startTime = Instant.now() var sum = 0.0 diff --git a/examples/src/main/kotlin/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/kscience/kmath/structures/ComplexND.kt index aa4b10ef2..b69590473 100644 --- a/examples/src/main/kotlin/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/kscience/kmath/structures/ComplexND.kt @@ -11,7 +11,7 @@ fun main() { val n = 1000 val realField = NDField.real(dim, dim) - val complexField = NDField.complex(dim, dim) + val complexField: ComplexNDField = NDField.complex(dim, dim) val realTime = measureTimeMillis { realField { diff --git a/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt index 778d811fd..b5130c92b 100644 --- a/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt @@ -33,7 +33,7 @@ fun main() { measureAndPrint("Automatic field addition") { autoField { var res: NDBuffer = one - repeat(n) { res += number(1.0) } + repeat(n) { res += 1.0 } } } @@ -45,14 +45,14 @@ fun main() { measureAndPrint("Specialized addition") { specializedField { var res: NDBuffer = one - repeat(n) { res += one } + repeat(n) { res += 1.0 } } } measureAndPrint("Nd4j specialized addition") { nd4jField { var res = one - repeat(n) { res += one } + repeat(n) { res += 1.0 } } } @@ -73,7 +73,7 @@ fun main() { genericField { var res: NDBuffer = one repeat(n) { - res += one // couldn't avoid using `one` due to resolution ambiguity } + res += 1.0 // couldn't avoid using `one` due to resolution ambiguity } } } } diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt index 80b164a7c..eadbc85ee 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt @@ -1,5 +1,6 @@ package kscience.kmath.ast +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.operations.* /** @@ -25,8 +26,11 @@ public object MstSpace : Space, NumericAlgebra { public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value) public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value) public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST.Unary = unaryOperationFunction(SpaceOperations.PLUS_OPERATION)(this) - public override operator fun MST.unaryMinus(): MST.Unary = unaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this) + public override operator fun MST.unaryPlus(): MST.Unary = + unaryOperationFunction(SpaceOperations.PLUS_OPERATION)(this) + + public override operator fun MST.unaryMinus(): MST.Unary = + unaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this) public override operator fun MST.minus(b: MST): MST.Binary = binaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this, b) @@ -44,7 +48,8 @@ public object MstSpace : Space, NumericAlgebra { /** * [Ring] over [MST] nodes. */ -public object MstRing : Ring, NumericAlgebra { +@OptIn(UnstableKMathAPI::class) +public object MstRing : Ring, RingWithNumbers { public override val zero: MST.Numeric get() = MstSpace.zero @@ -54,7 +59,9 @@ public object MstRing : Ring, NumericAlgebra { public override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value) public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b) public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k) - public override fun multiply(a: MST, b: MST): MST.Binary = binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) + public override fun multiply(a: MST, b: MST): MST.Binary = + binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) + public override operator fun MST.unaryPlus(): MST.Unary = MstSpace { +this@unaryPlus } public override operator fun MST.unaryMinus(): MST.Unary = MstSpace { -this@unaryMinus } public override operator fun MST.minus(b: MST): MST.Binary = MstSpace { this@minus - b } @@ -69,7 +76,8 @@ public object MstRing : Ring, NumericAlgebra { /** * [Field] over [MST] nodes. */ -public object MstField : Field { +@OptIn(UnstableKMathAPI::class) +public object MstField : Field, RingWithNumbers { public override val zero: MST.Numeric get() = MstRing.zero @@ -81,7 +89,9 @@ public object MstField : Field { public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k) public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) - public override fun divide(a: MST, b: MST): MST.Binary = binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) + public override fun divide(a: MST, b: MST): MST.Binary = + binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) + public override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } public override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } public override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b } @@ -89,13 +99,14 @@ public object MstField : Field { public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstRing.unaryOperationFunction(operation) + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + MstRing.unaryOperationFunction(operation) } /** * [ExtendedField] over [MST] nodes. */ -public object MstExtendedField : ExtendedField { +public object MstExtendedField : ExtendedField, NumericAlgebra { public override val zero: MST.Numeric get() = MstField.zero @@ -103,6 +114,7 @@ public object MstExtendedField : ExtendedField { get() = MstField.one public override fun symbol(value: String): MST.Symbolic = MstField.symbol(value) + public override fun number(value: Number): MST.Numeric = MstRing.number(value) public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) public override fun tan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.TAN_OPERATION)(arg) @@ -132,5 +144,6 @@ public object MstExtendedField : ExtendedField { public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstField.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstField.unaryOperationFunction(operation) + public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + MstField.unaryOperationFunction(operation) } diff --git a/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index 345babe8b..2912ddc4c 100644 --- a/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -1,7 +1,9 @@ package kscience.kmath.commons.expressions import kscience.kmath.expressions.* +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.operations.ExtendedField +import kscience.kmath.operations.RingWithNumbers import org.apache.commons.math3.analysis.differentiation.DerivativeStructure /** @@ -10,15 +12,18 @@ import org.apache.commons.math3.analysis.differentiation.DerivativeStructure * @property order The derivation order. * @property bindings The map of bindings values. All bindings are considered free parameters */ +@OptIn(UnstableKMathAPI::class) public class DerivativeStructureField( public val order: Int, bindings: Map, -) : ExtendedField, ExpressionAlgebra { +) : ExtendedField, ExpressionAlgebra, RingWithNumbers { public val numberOfVariables: Int = bindings.size public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } public override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) } + override fun number(value: Number): DerivativeStructure = const(value.toDouble()) + /** * A class that implements both [DerivativeStructure] and a [Symbol] */ diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index afbaf16e1..880a4e34c 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -7,8 +7,9 @@ import kscience.kmath.operations.* * * @param algebra The algebra to provide for Expressions built. */ -public abstract class FunctionalExpressionAlgebra>(public val algebra: A) : - ExpressionAlgebra> { +public abstract class FunctionalExpressionAlgebra>( + public val algebra: A, +) : ExpressionAlgebra> { /** * Builds an Expression of constant expression which does not depend on arguments. */ @@ -42,8 +43,9 @@ public abstract class FunctionalExpressionAlgebra>(public val /** * A context class for [Expression] construction for [Space] algebras. */ -public open class FunctionalExpressionSpace>(algebra: A) : - FunctionalExpressionAlgebra(algebra), Space> { +public open class FunctionalExpressionSpace>( + algebra: A, +) : FunctionalExpressionAlgebra(algebra), Space> { public override val zero: Expression get() = const(algebra.zero) /** @@ -71,8 +73,9 @@ public open class FunctionalExpressionSpace>(algebra: A) : super.binaryOperationFunction(operation) } -public open class FunctionalExpressionRing(algebra: A) : FunctionalExpressionSpace(algebra), - Ring> where A : Ring, A : NumericAlgebra { +public open class FunctionalExpressionRing>( + algebra: A, +) : FunctionalExpressionSpace(algebra), Ring> { public override val one: Expression get() = const(algebra.one) @@ -92,9 +95,8 @@ public open class FunctionalExpressionRing(algebra: A) : FunctionalExpress super.binaryOperationFunction(operation) } -public open class FunctionalExpressionField(algebra: A) : - FunctionalExpressionRing(algebra), Field> - where A : Field, A : NumericAlgebra { +public open class FunctionalExpressionField>(algebra: A) : + FunctionalExpressionRing(algebra), Field> { /** * Builds an Expression of division an expression by another one. */ @@ -111,9 +113,12 @@ public open class FunctionalExpressionField(algebra: A) : super.binaryOperationFunction(operation) } -public open class FunctionalExpressionExtendedField(algebra: A) : - FunctionalExpressionField(algebra), - ExtendedField> where A : ExtendedField, A : NumericAlgebra { +public open class FunctionalExpressionExtendedField>( + algebra: A, +) : FunctionalExpressionField(algebra), ExtendedField> { + + override fun number(value: Number): Expression = const(algebra.number(value)) + public override fun sin(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) @@ -135,7 +140,8 @@ public open class FunctionalExpressionExtendedField(algebra: A) : public override fun exp(arg: Expression): Expression = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - public override fun ln(arg: Expression): Expression = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) + public override fun ln(arg: Expression): Expression = + unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt index e8a894d23..0621e82bd 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt @@ -1,6 +1,7 @@ package kscience.kmath.expressions import kscience.kmath.linear.Point +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.operations.* import kscience.kmath.structures.asBuffer import kotlin.contracts.InvocationKind @@ -79,10 +80,11 @@ public fun > F.simpleAutoDiff( /** * Represents field in context of which functions can be derived. */ +@OptIn(UnstableKMathAPI::class) public open class SimpleAutoDiffField>( public val context: F, bindings: Map, -) : Field>, ExpressionAlgebra> { +) : Field>, ExpressionAlgebra>, RingWithNumbers> { public override val zero: AutoDiffValue get() = const(context.zero) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt index 767b58eba..1f93309a6 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt @@ -1,5 +1,7 @@ package kscience.kmath.linear +import kscience.kmath.structures.Matrix + /** * A marker interface representing some properties of matrices or additional transformations of them. Features are used * to optimize matrix operations performance in some cases or retrieve the APIs. @@ -30,7 +32,7 @@ public interface InverseMatrixFeature : MatrixFeature { /** * The inverse matrix of the matrix that owns this feature. */ - public val inverse: FeaturedMatrix + public val inverse: Matrix } /** diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index 24b417860..2bafd377e 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -88,85 +88,6 @@ public interface Algebra { public fun binaryOperation(operation: String, left: T, right: T): T = binaryOperationFunction(operation)(left, right) } -/** - * An algebraic structure where elements can have numeric representation. - * - * @param T the type of element of this structure. - */ -public interface NumericAlgebra : Algebra { - /** - * Wraps a number to [T] object. - * - * @param value the number to wrap. - * @return an object. - */ - public fun number(value: Number): T - - /** - * Dynamically dispatches a binary operation with the certain name with numeric first argument. - * - * This function must follow two properties: - * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [leftSideNumberOperation] overload: - * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. - * - * @param operation the name of operation. - * @return an operation. - */ - public fun leftSideNumberOperationFunction(operation: String): (left: Number, right: T) -> T = - { l, r -> binaryOperationFunction(operation)(number(l), r) } - - /** - * Dynamically invokes a binary operation with the certain name with numeric first argument. - * - * This function must follow two properties: - * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [leftSideNumberOperation] overload: - * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. - * - * @param operation the name of operation. - * @param left the first argument of operation. - * @param right the second argument of operation. - * @return a result of operation. - */ - public fun leftSideNumberOperation(operation: String, left: Number, right: T): T = - leftSideNumberOperationFunction(operation)(left, right) - - /** - * Dynamically dispatches a binary operation with the certain name with numeric first argument. - * - * This function must follow two properties: - * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: - * i.e. `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. - * - * @param operation the name of operation. - * @return an operation. - */ - public fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = - { l, r -> binaryOperationFunction(operation)(l, number(r)) } - - /** - * Dynamically invokes a binary operation with the certain name with numeric second argument. - * - * This function must follow two properties: - * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: - * i.e. `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. - * - * @param operation the name of operation. - * @param left the first argument of operation. - * @param right the second argument of operation. - * @return a result of operation. - */ - public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = - rightSideNumberOperationFunction(operation)(left, right) -} - /** * Call a block with an [Algebra] as receiver. */ @@ -341,47 +262,11 @@ public interface RingOperations : SpaceOperations { * * @param T the type of element of this ring. */ -public interface Ring : Space, RingOperations, NumericAlgebra { +public interface Ring : Space, RingOperations { /** * neutral operation for multiplication */ public val one: T - - public override fun number(value: Number): T = one * value.toDouble() - - /** - * Addition of element and scalar. - * - * @receiver the addend. - * @param b the augend. - */ - public operator fun T.plus(b: Number): T = this + number(b) - - /** - * Addition of scalar and element. - * - * @receiver the addend. - * @param b the augend. - */ - public operator fun Number.plus(b: T): T = b + this - - /** - * Subtraction of element from number. - * - * @receiver the minuend. - * @param b the subtrahend. - * @receiver the difference. - */ - public operator fun T.minus(b: Number): T = this - number(b) - - /** - * Subtraction of number from element. - * - * @receiver the minuend. - * @param b the subtrahend. - * @receiver the difference. - */ - public operator fun Number.minus(b: T): T = -b + this } /** diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/BigInt.kt index 20f289596..0be72e80c 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/BigInt.kt @@ -1,5 +1,6 @@ package kscience.kmath.operations +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.operations.BigInt.Companion.BASE import kscience.kmath.operations.BigInt.Companion.BASE_SIZE import kscience.kmath.structures.* @@ -16,7 +17,8 @@ public typealias TBase = ULong * * @author Robert Drynkin (https://github.com/robdrynkin) and Peter Klimai (https://github.com/pklimai) */ -public object BigIntField : Field { +@OptIn(UnstableKMathAPI::class) +public object BigIntField : Field, RingWithNumbers { override val zero: BigInt = BigInt.ZERO override val one: BigInt = BigInt.ONE 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 703931c7c..5695e6696 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt @@ -41,7 +41,7 @@ private val PI_DIV_2 = Complex(PI / 2, 0) /** * A field of [Complex]. */ -public object ComplexField : ExtendedField, Norm { +public object ComplexField : ExtendedField, Norm, RingWithNumbers { override val zero: Complex = 0.0.toComplex() override val one: Complex = 1.0.toComplex() @@ -156,7 +156,7 @@ public object ComplexField : ExtendedField, Norm { override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) - override fun symbol(value: String): Complex = if (value == "i") i else super.symbol(value) + override fun symbol(value: String): Complex = if (value == "i") i else super.symbol(value) } /** diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumericAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumericAlgebra.kt new file mode 100644 index 000000000..26f93fae8 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumericAlgebra.kt @@ -0,0 +1,125 @@ +package kscience.kmath.operations + +import kscience.kmath.misc.UnstableKMathAPI + +/** + * An algebraic structure where elements can have numeric representation. + * + * @param T the type of element of this structure. + */ +public interface NumericAlgebra : Algebra { + /** + * Wraps a number to [T] object. + * + * @param value the number to wrap. + * @return an object. + */ + public fun number(value: Number): T + + /** + * Dynamically dispatches a binary operation with the certain name with numeric first argument. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with the other [leftSideNumberOperation] overload: + * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. + * + * @param operation the name of operation. + * @return an operation. + */ + public fun leftSideNumberOperationFunction(operation: String): (left: Number, right: T) -> T = + { l, r -> binaryOperationFunction(operation)(number(l), r) } + + /** + * Dynamically invokes a binary operation with the certain name with numeric first argument. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with second [leftSideNumberOperation] overload: + * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * + * @param operation the name of operation. + * @param left the first argument of operation. + * @param right the second argument of operation. + * @return a result of operation. + */ + public fun leftSideNumberOperation(operation: String, left: Number, right: T): T = + leftSideNumberOperationFunction(operation)(left, right) + + /** + * Dynamically dispatches a binary operation with the certain name with numeric first argument. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: + * i.e. `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * + * @param operation the name of operation. + * @return an operation. + */ + public fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = + { l, r -> binaryOperationFunction(operation)(l, number(r)) } + + /** + * Dynamically invokes a binary operation with the certain name with numeric second argument. + * + * This function must follow two properties: + * + * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. + * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: + * i.e. `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. + * + * @param operation the name of operation. + * @param left the first argument of operation. + * @param right the second argument of operation. + * @return a result of operation. + */ + public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = + rightSideNumberOperationFunction(operation)(left, right) +} + +/** + * A combination of [NumericAlgebra] and [Ring] that adds intrinsic simple operations on numbers like `T+1` + * TODO to be removed and replaced by extensions after multiple receivers are there + */ +@UnstableKMathAPI +public interface RingWithNumbers: Ring, NumericAlgebra{ + public override fun number(value: Number): T = one * value + + /** + * Addition of element and scalar. + * + * @receiver the addend. + * @param b the augend. + */ + public operator fun T.plus(b: Number): T = this + number(b) + + /** + * Addition of scalar and element. + * + * @receiver the addend. + * @param b the augend. + */ + public operator fun Number.plus(b: T): T = b + this + + /** + * Subtraction of element from number. + * + * @receiver the minuend. + * @param b the subtrahend. + * @receiver the difference. + */ + public operator fun T.minus(b: Number): T = this - number(b) + + /** + * Subtraction of number from element. + * + * @receiver the minuend. + * @param b the subtrahend. + * @receiver the difference. + */ + public operator fun Number.minus(b: T): T = -b + this +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/numbers.kt similarity index 97% rename from kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt rename to kmath-core/src/commonMain/kotlin/kscience/kmath/operations/numbers.kt index a7b73d5e0..de3818aa6 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/NumberAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/numbers.kt @@ -37,7 +37,7 @@ public interface ExtendedFieldOperations : /** * Advanced Number-like field that implements basic operations. */ -public interface ExtendedField : ExtendedFieldOperations, Field { +public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra { public override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2 public override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2 public override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) @@ -80,6 +80,8 @@ public object RealField : ExtendedField, Norm { public override val one: Double get() = 1.0 + override fun number(value: Number): Double = value.toDouble() + public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { PowerOperations.POW_OPERATION -> ::power @@ -131,10 +133,13 @@ public object FloatField : ExtendedField, Norm { public override val one: Float get() = 1.0f - public override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = when (operation) { - PowerOperations.POW_OPERATION -> ::power - else -> super.binaryOperationFunction(operation) - } + override fun number(value: Number): Float = value.toFloat() + + public override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = + when (operation) { + PowerOperations.POW_OPERATION -> ::power + else -> super.binaryOperationFunction(operation) + } public override inline fun add(a: Float, b: Float): Float = a + b public override inline fun multiply(a: Float, k: Number): Float = a * k.toFloat() diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/ComplexNDField.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/ComplexNDField.kt index f1f1074e5..6de69cabe 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/ComplexNDField.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/ComplexNDField.kt @@ -1,9 +1,7 @@ package kscience.kmath.structures -import kscience.kmath.operations.Complex -import kscience.kmath.operations.ComplexField -import kscience.kmath.operations.FieldElement -import kscience.kmath.operations.complex +import kscience.kmath.misc.UnstableKMathAPI +import kscience.kmath.operations.* import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -12,15 +10,22 @@ public typealias ComplexNDElement = BufferedNDFieldElement, - ExtendedNDField> { + ExtendedNDField>, + RingWithNumbers>{ override val strides: Strides = DefaultStrides(shape) override val elementContext: ComplexField get() = ComplexField override val zero: ComplexNDElement by lazy { produce { zero } } override val one: ComplexNDElement by lazy { produce { one } } + override fun number(value: Number): NDBuffer { + val c = value.toComplex() + return produce { c } + } + public inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Complex): Buffer = Buffer.complex(size) { initializer(it) } @@ -29,7 +34,7 @@ public class ComplexNDField(override val shape: IntArray) : */ override fun map( arg: NDBuffer, - transform: ComplexField.(Complex) -> Complex + transform: ComplexField.(Complex) -> Complex, ): ComplexNDElement { check(arg) val array = buildBuffer(arg.strides.linearSize) { offset -> ComplexField.transform(arg.buffer[offset]) } @@ -43,7 +48,7 @@ public class ComplexNDField(override val shape: IntArray) : override fun mapIndexed( arg: NDBuffer, - transform: ComplexField.(index: IntArray, Complex) -> Complex + transform: ComplexField.(index: IntArray, Complex) -> Complex, ): ComplexNDElement { check(arg) @@ -60,7 +65,7 @@ public class ComplexNDField(override val shape: IntArray) : override fun combine( a: NDBuffer, b: NDBuffer, - transform: ComplexField.(Complex, Complex) -> Complex + transform: ComplexField.(Complex, Complex) -> Complex, ): ComplexNDElement { check(a, b) @@ -141,7 +146,7 @@ public fun NDField.Companion.complex(vararg shape: Int): ComplexNDField = Comple public fun NDElement.Companion.complex( vararg shape: Int, - initializer: ComplexField.(IntArray) -> Complex + initializer: ComplexField.(IntArray) -> Complex, ): ComplexNDElement = NDField.complex(*shape).produce(initializer) /** diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealBufferField.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealBufferField.kt index f7b2ee31e..3f4d15c4d 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealBufferField.kt @@ -150,6 +150,8 @@ public class RealBufferField(public val size: Int) : ExtendedField by lazy { RealBuffer(size) { 0.0 } } public override val one: Buffer by lazy { RealBuffer(size) { 1.0 } } + override fun number(value: Number): Buffer = RealBuffer(size) { value.toDouble() } + public override fun add(a: Buffer, b: Buffer): RealBuffer { require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } return RealBufferFieldOperations.add(a, b) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt index ed28fb9f2..3eb1dc4ca 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt @@ -1,13 +1,17 @@ package kscience.kmath.structures +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.operations.FieldElement import kscience.kmath.operations.RealField +import kscience.kmath.operations.RingWithNumbers public typealias RealNDElement = BufferedNDFieldElement +@OptIn(UnstableKMathAPI::class) public class RealNDField(override val shape: IntArray) : BufferedNDField, - ExtendedNDField> { + ExtendedNDField>, + RingWithNumbers>{ override val strides: Strides = DefaultStrides(shape) @@ -15,7 +19,12 @@ public class RealNDField(override val shape: IntArray) : override val zero: RealNDElement by lazy { produce { zero } } override val one: RealNDElement by lazy { produce { one } } - public inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer = + override fun number(value: Number): NDBuffer { + val d = value.toDouble() + return produce { d } + } + + private inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer = RealBuffer(DoubleArray(size) { initializer(it) }) /** @@ -59,7 +68,8 @@ public class RealNDField(override val shape: IntArray) : check(a, b) return BufferedNDFieldElement( this, - buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) }) + buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) } + ) } override fun NDBuffer.toElement(): FieldElement, *, out BufferedNDField> = diff --git a/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NDFieldTest.kt index b763ec7de..1129a8a36 100644 --- a/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NDFieldTest.kt @@ -1,14 +1,13 @@ package kscience.kmath.structures import kscience.kmath.operations.internal.FieldVerifier -import kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals internal class NDFieldTest { @Test fun verify() { - (NDField.real(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } + NDField.real(12, 32).run { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } } @Test diff --git a/kmath-core/src/jvmMain/kotlin/kscience/kmath/operations/BigNumbers.kt b/kmath-core/src/jvmMain/kotlin/kscience/kmath/operations/BigNumbers.kt index 2f0978237..9bd6a9fc4 100644 --- a/kmath-core/src/jvmMain/kotlin/kscience/kmath/operations/BigNumbers.kt +++ b/kmath-core/src/jvmMain/kotlin/kscience/kmath/operations/BigNumbers.kt @@ -7,7 +7,7 @@ import java.math.MathContext /** * A field over [BigInteger]. */ -public object JBigIntegerField : Field { +public object JBigIntegerField : Field, NumericAlgebra { public override val zero: BigInteger get() = BigInteger.ZERO @@ -28,9 +28,9 @@ public object JBigIntegerField : Field { * * @property mathContext the [MathContext] to use. */ -public abstract class JBigDecimalFieldBase internal constructor(public val mathContext: MathContext = MathContext.DECIMAL64) : - Field, - PowerOperations { +public abstract class JBigDecimalFieldBase internal constructor( + private val mathContext: MathContext = MathContext.DECIMAL64, +) : Field, PowerOperations, NumericAlgebra { public override val zero: BigDecimal get() = BigDecimal.ZERO diff --git a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt index 5b7d0a01b..a7d571b58 100644 --- a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt +++ b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt @@ -12,8 +12,10 @@ import org.ejml.simple.SimpleMatrix * @property origin the underlying [SimpleMatrix]. * @author Iaroslav Postovalov */ -public class EjmlMatrix(public val origin: SimpleMatrix, features: Set = emptySet()) : - FeaturedMatrix { +public class EjmlMatrix( + public val origin: SimpleMatrix, + features: Set = emptySet() +) : FeaturedMatrix { public override val rowNum: Int get() = origin.numRows() @@ -88,11 +90,7 @@ public class EjmlMatrix(public val origin: SimpleMatrix, features: Set ?: return false) } - public override fun hashCode(): Int { - var result = origin.hashCode() - result = 31 * result + features.hashCode() - return result - } + public override fun hashCode(): Int = origin.hashCode() - public override fun toString(): String = "EjmlMatrix(origin=$origin, features=$features)" + public override fun toString(): String = "EjmlMatrix($origin)" } diff --git a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt index f8791b72c..c8789a4a7 100644 --- a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt +++ b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt @@ -1,7 +1,9 @@ package kscience.kmath.ejml +import kscience.kmath.linear.InverseMatrixFeature import kscience.kmath.linear.MatrixContext import kscience.kmath.linear.Point +import kscience.kmath.linear.getFeature import kscience.kmath.structures.Matrix import org.ejml.simple.SimpleMatrix @@ -77,3 +79,7 @@ public fun EjmlMatrixContext.solve(a: Matrix, b: Matrix): EjmlMa */ public fun EjmlMatrixContext.solve(a: Matrix, b: Point): EjmlVector = EjmlVector(a.toEjml().origin.solve(b.toEjml().origin)) + +public fun EjmlMatrix.inverted(): EjmlMatrix = getFeature>()!!.inverse as EjmlMatrix + +public fun EjmlMatrixContext.inverse(matrix: Matrix): Matrix = matrix.toEjml().inverted() \ No newline at end of file diff --git a/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/Nd4jArrayAlgebra.kt b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/Nd4jArrayAlgebra.kt index a8c874fc3..db2a44861 100644 --- a/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/Nd4jArrayAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/Nd4jArrayAlgebra.kt @@ -1,5 +1,6 @@ package kscience.kmath.nd4j +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.operations.* import kscience.kmath.structures.NDAlgebra import kscience.kmath.structures.NDField @@ -35,7 +36,7 @@ public interface Nd4jArrayAlgebra : NDAlgebra> public override fun mapIndexed( arg: Nd4jArrayStructure, - transform: C.(index: IntArray, T) -> T + transform: C.(index: IntArray, T) -> T, ): Nd4jArrayStructure { check(arg) val new = Nd4j.create(*shape).wrap() @@ -46,7 +47,7 @@ public interface Nd4jArrayAlgebra : NDAlgebra> public override fun combine( a: Nd4jArrayStructure, b: Nd4jArrayStructure, - transform: C.(T, T) -> T + transform: C.(T, T) -> T, ): Nd4jArrayStructure { check(a, b) val new = Nd4j.create(*shape).wrap() @@ -61,8 +62,8 @@ public interface Nd4jArrayAlgebra : NDAlgebra> * @param T the type of the element contained in ND structure. * @param S the type of space of structure elements. */ -public interface Nd4jArraySpace : NDSpace>, - Nd4jArrayAlgebra where S : Space { +public interface Nd4jArraySpace> : NDSpace>, Nd4jArrayAlgebra { + public override val zero: Nd4jArrayStructure get() = Nd4j.zeros(*shape).wrap() @@ -103,7 +104,9 @@ public interface Nd4jArraySpace : NDSpace>, * @param T the type of the element contained in ND structure. * @param R the type of ring of structure elements. */ -public interface Nd4jArrayRing : NDRing>, Nd4jArraySpace where R : Ring { +@OptIn(UnstableKMathAPI::class) +public interface Nd4jArrayRing> : NDRing>, Nd4jArraySpace { + public override val one: Nd4jArrayStructure get() = Nd4j.ones(*shape).wrap() @@ -111,21 +114,21 @@ public interface Nd4jArrayRing : NDRing>, Nd4j check(a, b) return a.ndArray.mul(b.ndArray).wrap() } - - public override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { - check(this) - return ndArray.sub(b).wrap() - } - - public override operator fun Nd4jArrayStructure.plus(b: Number): Nd4jArrayStructure { - check(this) - return ndArray.add(b).wrap() - } - - public override operator fun Number.minus(b: Nd4jArrayStructure): Nd4jArrayStructure { - check(b) - return b.ndArray.rsub(this).wrap() - } +// +// public override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { +// check(this) +// return ndArray.sub(b).wrap() +// } +// +// public override operator fun Nd4jArrayStructure.plus(b: Number): Nd4jArrayStructure { +// check(this) +// return ndArray.add(b).wrap() +// } +// +// public override operator fun Number.minus(b: Nd4jArrayStructure): Nd4jArrayStructure { +// check(b) +// return b.ndArray.rsub(this).wrap() +// } public companion object { private val intNd4jArrayRingCache: ThreadLocal> = @@ -165,7 +168,8 @@ public interface Nd4jArrayRing : NDRing>, Nd4j * @param N the type of ND structure. * @param F the type field of structure elements. */ -public interface Nd4jArrayField : NDField>, Nd4jArrayRing where F : Field { +public interface Nd4jArrayField> : NDField>, Nd4jArrayRing { + public override fun divide(a: Nd4jArrayStructure, b: Nd4jArrayStructure): Nd4jArrayStructure { check(a, b) return a.ndArray.div(b.ndArray).wrap() diff --git a/settings.gradle.kts b/settings.gradle.kts index 025e4a3c6..a1ea40148 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,8 +8,8 @@ pluginManagement { maven("https://dl.bintray.com/kotlin/kotlinx") } - val toolsVersion = "0.7.2-dev-2" - val kotlinVersion = "1.4.21" + val toolsVersion = "0.7.3-1.4.30-RC" + val kotlinVersion = "1.4.30-RC" plugins { id("kotlinx.benchmark") version "0.2.0-dev-20" From 4c256a9f14f4db251cb2797f8ddcfb1b88ab8dac Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 19 Jan 2021 19:32:13 +0300 Subject: [PATCH 50/55] Features refactoring. --- CHANGELOG.md | 1 + .../kscience/kmath/commons/linear/CMMatrix.kt | 50 +++++----- .../kscience/kmath/linear/BufferMatrix.kt | 26 +++--- ...UPDecomposition.kt => LupDecomposition.kt} | 58 +++++++----- .../kscience/kmath/linear/MatrixBuilder.kt | 15 ++- .../kscience/kmath/linear/MatrixContext.kt | 2 - .../kscience/kmath/linear/MatrixFeatures.kt | 26 +++--- .../{FeaturedMatrix.kt => MatrixWrapper.kt} | 78 +++++++++------- .../kmath/linear/RealMatrixContext.kt | 20 +--- .../kscience/kmath/linear/VirtualMatrix.kt | 31 +------ .../kscience/kmath/operations/numbers.kt | 16 +++- .../kscience/kmath/structures/NDStructure.kt | 11 +++ .../kscience/kmath/structures/Structure2D.kt | 9 +- .../kscience/kmath/dimensions/Wrappers.kt | 9 +- .../kotlin/kscience/kmath/ejml/EjmlMatrix.kt | 91 ++++++++----------- .../kscience/kmath/ejml/EjmlMatrixContext.kt | 21 +++-- .../kscience/kmath/ejml/EjmlMatrixTest.kt | 5 +- .../kotlin/kscience/kmath/real/RealMatrix.kt | 8 +- .../kaceince/kmath/real/RealMatrixTest.kt | 3 +- 19 files changed, 236 insertions(+), 244 deletions(-) rename kmath-core/src/commonMain/kotlin/kscience/kmath/linear/{LUPDecomposition.kt => LupDecomposition.kt} (78%) rename kmath-core/src/commonMain/kotlin/kscience/kmath/linear/{FeaturedMatrix.kt => MatrixWrapper.kt} (50%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 840733d92..27d4dd1aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ - EjmlMatrix context is an object - Matrix LUP `inverse` renamed to `inverseWithLUP` - `NumericAlgebra` moved outside of regular algebra chain (`Ring` no longer implements it). +- Features moved to NDStructure and became transparent. ### Deprecated diff --git a/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt index 49888f8d6..48b6e0ef1 100644 --- a/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt +++ b/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt @@ -1,42 +1,28 @@ package kscience.kmath.commons.linear -import kscience.kmath.linear.* +import kscience.kmath.linear.DiagonalFeature +import kscience.kmath.linear.MatrixContext +import kscience.kmath.linear.MatrixWrapper +import kscience.kmath.linear.Point +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.structures.Matrix -import kscience.kmath.structures.NDStructure import org.apache.commons.math3.linear.* +import kotlin.reflect.KClass +import kotlin.reflect.cast -public class CMMatrix(public val origin: RealMatrix, features: Set? = null) : FeaturedMatrix { +public inline class CMMatrix(public val origin: RealMatrix) : Matrix { public override val rowNum: Int get() = origin.rowDimension public override val colNum: Int get() = origin.columnDimension - public override val features: Set = features ?: sequence { - if (origin is DiagonalMatrix) yield(DiagonalFeature) - }.toHashSet() - - public override fun suggestFeature(vararg features: MatrixFeature): CMMatrix = - CMMatrix(origin, this.features + features) + @UnstableKMathAPI + override fun getFeature(type: KClass): T? = when (type) { + DiagonalFeature::class -> if (origin is DiagonalMatrix) DiagonalFeature else null + else -> null + }?.let { type.cast(it) } public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) - - public override fun equals(other: Any?): Boolean { - return NDStructure.equals(this, other as? NDStructure<*> ?: return false) - } - - public override fun hashCode(): Int { - var result = origin.hashCode() - result = 31 * result + features.hashCode() - return result - } } -//TODO move inside context -public fun Matrix.toCM(): CMMatrix = if (this is CMMatrix) { - this -} else { - //TODO add feature analysis - val array = Array(rowNum) { i -> DoubleArray(colNum) { j -> get(i, j) } } - CMMatrix(Array2DRowRealMatrix(array)) -} public fun RealMatrix.asMatrix(): CMMatrix = CMMatrix(this) @@ -61,6 +47,16 @@ public object CMMatrixContext : MatrixContext { return CMMatrix(Array2DRowRealMatrix(array)) } + public fun Matrix.toCM(): CMMatrix = when { + this is CMMatrix -> this + this is MatrixWrapper && matrix is CMMatrix -> matrix as CMMatrix + else -> { + //TODO add feature analysis + val array = Array(rowNum) { i -> DoubleArray(colNum) { j -> get(i, j) } } + CMMatrix(Array2DRowRealMatrix(array)) + } + } + public override fun Matrix.dot(other: Matrix): CMMatrix = CMMatrix(toCM().origin.multiply(other.toCM().origin)) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt index 402161207..80460baca 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt @@ -1,10 +1,7 @@ package kscience.kmath.linear import kscience.kmath.operations.Ring -import kscience.kmath.structures.Buffer -import kscience.kmath.structures.BufferFactory -import kscience.kmath.structures.NDStructure -import kscience.kmath.structures.asSequence +import kscience.kmath.structures.* /** * Basic implementation of Matrix space based on [NDStructure] @@ -27,8 +24,7 @@ public class BufferMatrix( public override val rowNum: Int, public override val colNum: Int, public val buffer: Buffer, - public override val features: Set = emptySet(), -) : FeaturedMatrix { +) : Matrix { init { require(buffer.size == rowNum * colNum) { "Dimension mismatch for matrix structure" } @@ -36,9 +32,6 @@ public class BufferMatrix( override val shape: IntArray get() = intArrayOf(rowNum, colNum) - public override fun suggestFeature(vararg features: MatrixFeature): BufferMatrix = - BufferMatrix(rowNum, colNum, buffer, this.features + features) - 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] @@ -50,23 +43,26 @@ public class BufferMatrix( if (this === other) return true return when (other) { - is NDStructure<*> -> return NDStructure.equals(this, other) + is NDStructure<*> -> NDStructure.equals(this, other) else -> false } } - public override fun hashCode(): Int { - var result = buffer.hashCode() - result = 31 * result + features.hashCode() + override fun hashCode(): Int { + var result = rowNum + result = 31 * result + colNum + result = 31 * result + buffer.hashCode() return result } public override fun toString(): String { return if (rowNum <= 5 && colNum <= 5) - "Matrix(rowsNum = $rowNum, colNum = $colNum, features=$features)\n" + + "Matrix(rowsNum = $rowNum, colNum = $colNum)\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)" } + + } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt similarity index 78% rename from kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt rename to kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt index 75acaf8a1..f4f998da2 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LUPDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt @@ -1,13 +1,14 @@ package kscience.kmath.linear +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.operations.* import kscience.kmath.structures.* /** * Common implementation of [LupDecompositionFeature]. */ -public class LUPDecomposition( - public val context: MatrixContext>, +public class LupDecomposition( + public val context: MatrixContext>, public val elementContext: Field, public val lu: Matrix, public val pivot: IntArray, @@ -18,13 +19,13 @@ public class LUPDecomposition( * * L is a lower-triangular matrix with [Ring.one] in diagonal */ - override val l: FeaturedMatrix = VirtualMatrix(lu.shape[0], lu.shape[1], setOf(LFeature)) { i, j -> + override val l: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> when { j < i -> lu[i, j] j == i -> elementContext.one else -> elementContext.zero } - } + } + LFeature /** @@ -32,9 +33,9 @@ public class LUPDecomposition( * * U is an upper-triangular matrix including the diagonal */ - override val u: FeaturedMatrix = VirtualMatrix(lu.shape[0], lu.shape[1], setOf(UFeature)) { i, j -> + override val u: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> if (j >= i) lu[i, j] else elementContext.zero - } + } + UFeature /** * Returns the P rows permutation matrix. @@ -42,7 +43,7 @@ public class LUPDecomposition( * P is a sparse matrix with exactly one element set to [Ring.one] in * each row and each column, all other elements being set to [Ring.zero]. */ - override val p: FeaturedMatrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> + override val p: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> if (j == pivot[i]) elementContext.one else elementContext.zero } @@ -63,12 +64,12 @@ internal fun , F : Field> GenericMatrixContext.abs /** * Create a lup decomposition of generic matrix. */ -public fun > MatrixContext>.lup( +public fun > MatrixContext>.lup( factory: MutableBufferFactory, elementContext: Field, matrix: Matrix, checkSingular: (T) -> Boolean, -): LUPDecomposition { +): LupDecomposition { require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" } val m = matrix.colNum val pivot = IntArray(matrix.rowNum) @@ -137,23 +138,23 @@ public fun > MatrixContext>.lup( for (row in col + 1 until m) lu[row, col] /= luDiag } - return LUPDecomposition(this@lup, elementContext, lu.collect(), pivot, even) + return LupDecomposition(this@lup, elementContext, lu.collect(), pivot, even) } } } -public inline fun , F : Field> GenericMatrixContext>.lup( +public inline fun , F : Field> GenericMatrixContext>.lup( matrix: Matrix, noinline checkSingular: (T) -> Boolean, -): LUPDecomposition = lup(MutableBuffer.Companion::auto, elementContext, matrix, checkSingular) +): LupDecomposition = lup(MutableBuffer.Companion::auto, elementContext, matrix, checkSingular) -public fun MatrixContext>.lup(matrix: Matrix): LUPDecomposition = +public fun MatrixContext>.lup(matrix: Matrix): LupDecomposition = lup(Buffer.Companion::real, RealField, matrix) { it < 1e-11 } -public fun LUPDecomposition.solveWithLUP( +public fun LupDecomposition.solveWithLUP( factory: MutableBufferFactory, - matrix: Matrix -): FeaturedMatrix { + matrix: Matrix, +): Matrix { require(matrix.rowNum == pivot.size) { "Matrix dimension mismatch. Expected ${pivot.size}, but got ${matrix.colNum}" } BufferAccessor2D(matrix.rowNum, matrix.colNum, factory).run { @@ -198,25 +199,40 @@ public fun LUPDecomposition.solveWithLUP( } } -public inline fun LUPDecomposition.solveWithLUP(matrix: Matrix): Matrix = +public inline fun LupDecomposition.solveWithLUP(matrix: Matrix): Matrix = solveWithLUP(MutableBuffer.Companion::auto, matrix) /** * Solve a linear equation **a*x = b** using LUP decomposition */ -public inline fun , F : Field> GenericMatrixContext>.solveWithLUP( +@OptIn(UnstableKMathAPI::class) +public inline fun , F : Field> GenericMatrixContext>.solveWithLUP( a: Matrix, b: Matrix, noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, noinline checkSingular: (T) -> Boolean, -): FeaturedMatrix { +): Matrix { // Use existing decomposition if it is provided by matrix val decomposition = a.getFeature() ?: lup(bufferFactory, elementContext, a, checkSingular) return decomposition.solveWithLUP(bufferFactory, b) } -public inline fun , F : Field> GenericMatrixContext>.inverseWithLUP( +public inline fun , F : Field> GenericMatrixContext>.inverseWithLUP( matrix: Matrix, noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, noinline checkSingular: (T) -> Boolean, -): FeaturedMatrix = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) +): Matrix = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) + + +public fun RealMatrixContext.solveWithLUP(a: Matrix, b: Matrix): Matrix { + // Use existing decomposition if it is provided by matrix + val bufferFactory: MutableBufferFactory = MutableBuffer.Companion::real + val decomposition: LupDecomposition = a.getFeature() ?: lup(bufferFactory, RealField, a) { it < 1e-11 } + return decomposition.solveWithLUP(bufferFactory, b) +} + +/** + * Inverses a square matrix using LUP decomposition. Non square matrix will throw a error. + */ +public fun RealMatrixContext.inverseWithLUP(matrix: Matrix): Matrix = + solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixBuilder.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixBuilder.kt index 91c1ec824..c0c209248 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixBuilder.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixBuilder.kt @@ -1,12 +1,9 @@ package kscience.kmath.linear -import kscience.kmath.structures.Buffer -import kscience.kmath.structures.BufferFactory -import kscience.kmath.structures.Structure2D -import kscience.kmath.structures.asBuffer +import kscience.kmath.structures.* public class MatrixBuilder(public val rows: Int, public val columns: Int) { - public operator fun invoke(vararg elements: T): FeaturedMatrix { + public operator fun invoke(vararg elements: T): Matrix { require(rows * columns == elements.size) { "The number of elements ${elements.size} is not equal $rows * $columns" } val buffer = elements.asBuffer() return BufferMatrix(rows, columns, buffer) @@ -17,7 +14,7 @@ public class MatrixBuilder(public val rows: Int, public val columns: Int) { public fun Structure2D.Companion.build(rows: Int, columns: Int): MatrixBuilder = MatrixBuilder(rows, columns) -public fun Structure2D.Companion.row(vararg values: T): FeaturedMatrix { +public fun Structure2D.Companion.row(vararg values: T): Matrix { val buffer = values.asBuffer() return BufferMatrix(1, values.size, buffer) } @@ -26,12 +23,12 @@ public inline fun Structure2D.Companion.row( size: Int, factory: BufferFactory = Buffer.Companion::auto, noinline builder: (Int) -> T -): FeaturedMatrix { +): Matrix { val buffer = factory(size, builder) return BufferMatrix(1, size, buffer) } -public fun Structure2D.Companion.column(vararg values: T): FeaturedMatrix { +public fun Structure2D.Companion.column(vararg values: T): Matrix { val buffer = values.asBuffer() return BufferMatrix(values.size, 1, buffer) } @@ -40,7 +37,7 @@ public inline fun Structure2D.Companion.column( size: Int, factory: BufferFactory = Buffer.Companion::auto, noinline builder: (Int) -> T -): FeaturedMatrix { +): Matrix { val buffer = factory(size, builder) return BufferMatrix(size, 1, buffer) } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt index 8c28a240f..59a41f840 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixContext.kt @@ -133,8 +133,6 @@ public interface GenericMatrixContext, out M : Matrix> : public override fun multiply(a: Matrix, k: Number): M = produce(a.rowNum, a.colNum) { i, j -> elementContext { a[i, j] * k } } - public operator fun Number.times(matrix: FeaturedMatrix): M = multiply(matrix, this) - public override operator fun Matrix.times(value: T): M = produce(rowNum, colNum) { i, j -> elementContext { get(i, j) * value } } } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt index 1f93309a6..e61feec6c 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixFeatures.kt @@ -11,17 +11,19 @@ public interface MatrixFeature /** * Matrices with this feature are considered to have only diagonal non-null elements. */ -public object DiagonalFeature : MatrixFeature +public interface DiagonalFeature : MatrixFeature{ + public companion object: DiagonalFeature +} /** * Matrices with this feature have all zero elements. */ -public object ZeroFeature : MatrixFeature +public object ZeroFeature : DiagonalFeature /** * Matrices with this feature have unit elements on diagonal and zero elements in all other places. */ -public object UnitFeature : MatrixFeature +public object UnitFeature : DiagonalFeature /** * Matrices with this feature can be inverted: [inverse] = `a`-1 where `a` is the owning matrix. @@ -76,17 +78,17 @@ public interface LupDecompositionFeature : MatrixFeature { /** * The lower triangular matrix in this decomposition. It may have [LFeature]. */ - public val l: FeaturedMatrix + public val l: Matrix /** * The upper triangular matrix in this decomposition. It may have [UFeature]. */ - public val u: FeaturedMatrix + public val u: Matrix /** * The permutation matrix in this decomposition. */ - public val p: FeaturedMatrix + public val p: Matrix } /** @@ -104,12 +106,12 @@ public interface QRDecompositionFeature : MatrixFeature { /** * The orthogonal matrix in this decomposition. It may have [OrthogonalFeature]. */ - public val q: FeaturedMatrix + public val q: Matrix /** * The upper triangular matrix in this decomposition. It may have [UFeature]. */ - public val r: FeaturedMatrix + public val r: Matrix } /** @@ -122,7 +124,7 @@ public interface CholeskyDecompositionFeature : MatrixFeature { /** * The triangular matrix in this decomposition. It may have either [UFeature] or [LFeature]. */ - public val l: FeaturedMatrix + public val l: Matrix } /** @@ -135,17 +137,17 @@ public interface SingularValueDecompositionFeature : MatrixFeature { /** * The matrix in this decomposition. It is unitary, and it consists from left singular vectors. */ - public val u: FeaturedMatrix + public val u: Matrix /** * The matrix in this decomposition. Its main diagonal elements are singular values. */ - public val s: FeaturedMatrix + public val s: Matrix /** * The matrix in this decomposition. It is unitary, and it consists from right singular vectors. */ - public val v: FeaturedMatrix + public val v: Matrix /** * The buffer of singular values of this SVD. diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/FeaturedMatrix.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt similarity index 50% rename from kmath-core/src/commonMain/kotlin/kscience/kmath/linear/FeaturedMatrix.kt rename to kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt index 119f5d844..bbe9c1195 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/FeaturedMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt @@ -1,35 +1,57 @@ package kscience.kmath.linear +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.operations.Ring import kscience.kmath.structures.Matrix import kscience.kmath.structures.Structure2D import kscience.kmath.structures.asBuffer +import kscience.kmath.structures.getFeature import kotlin.math.sqrt +import kotlin.reflect.KClass +import kotlin.reflect.safeCast /** * A [Matrix] that holds [MatrixFeature] objects. * * @param T the type of items. */ -public interface FeaturedMatrix : Matrix { - public override val shape: IntArray get() = intArrayOf(rowNum, colNum) +public class MatrixWrapper( + public val matrix: Matrix, + public val features: Set, +) : Matrix by matrix { /** - * The set of features this matrix possesses. + * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria */ - public val features: Set + @UnstableKMathAPI + override fun getFeature(type: KClass): T? = type.safeCast(features.find { type.isInstance(it) }) - /** - * Suggest new feature for this matrix. The result is the new matrix that may or may not reuse existing data structure. - * - * The implementation does not guarantee to check that matrix actually have the feature, so one should be careful to - * add only those features that are valid. - */ - public fun suggestFeature(vararg features: MatrixFeature): FeaturedMatrix - - public companion object + override fun equals(other: Any?): Boolean = matrix == other + override fun hashCode(): Int = matrix.hashCode() + override fun toString(): String { + return "MatrixWrapper(matrix=$matrix, features=$features)" + } } +/** + * Add a single feature to a [Matrix] + */ +public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixWrapper = if (this is MatrixWrapper) { + MatrixWrapper(matrix, features + newFeature) +} else { + MatrixWrapper(this, setOf(newFeature)) +} + +/** + * Add a collection of features to a [Matrix] + */ +public operator fun Matrix.plus(newFeatures: Collection): MatrixWrapper = + if (this is MatrixWrapper) { + MatrixWrapper(matrix, features + newFeatures) + } else { + MatrixWrapper(this, newFeatures.toSet()) + } + public inline fun Structure2D.Companion.real( rows: Int, columns: Int, @@ -39,51 +61,37 @@ public inline fun Structure2D.Companion.real( /** * Build a square matrix from given elements. */ -public fun Structure2D.Companion.square(vararg elements: T): FeaturedMatrix { +public fun Structure2D.Companion.square(vararg elements: T): Matrix { val size: Int = sqrt(elements.size.toDouble()).toInt() require(size * size == elements.size) { "The number of elements ${elements.size} is not a full square" } val buffer = elements.asBuffer() return BufferMatrix(size, size, buffer) } -public val Matrix<*>.features: Set get() = (this as? FeaturedMatrix)?.features ?: emptySet() - -/** - * Check if matrix has the given feature class - */ -public inline fun Matrix<*>.hasFeature(): Boolean = - features.find { it is T } != null - -/** - * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria - */ -public inline fun Matrix<*>.getFeature(): T? = - features.filterIsInstance().firstOrNull() - /** * Diagonal matrix of ones. The matrix is virtual no actual matrix is created */ -public fun > GenericMatrixContext.one(rows: Int, columns: Int): FeaturedMatrix = - VirtualMatrix(rows, columns, DiagonalFeature) { i, j -> +public fun > GenericMatrixContext.one(rows: Int, columns: Int): Matrix = + VirtualMatrix(rows, columns) { i, j -> if (i == j) elementContext.one else elementContext.zero - } + } + UnitFeature /** * A virtual matrix of zeroes */ -public fun > GenericMatrixContext.zero(rows: Int, columns: Int): FeaturedMatrix = - VirtualMatrix(rows, columns) { _, _ -> elementContext.zero } +public fun > GenericMatrixContext.zero(rows: Int, columns: Int): Matrix = + VirtualMatrix(rows, columns) { _, _ -> elementContext.zero } + ZeroFeature public class TransposedFeature(public val original: Matrix) : MatrixFeature /** * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` */ +@OptIn(UnstableKMathAPI::class) public fun Matrix.transpose(): Matrix { return getFeature>()?.original ?: VirtualMatrix( colNum, rowNum, - setOf(TransposedFeature(this)) - ) { i, j -> get(j, i) } + ) { i, j -> get(j, i) } + TransposedFeature(this) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt index 90e251c3a..8e197672f 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/RealMatrixContext.kt @@ -1,9 +1,6 @@ package kscience.kmath.linear -import kscience.kmath.operations.RealField import kscience.kmath.structures.Matrix -import kscience.kmath.structures.MutableBuffer -import kscience.kmath.structures.MutableBufferFactory import kscience.kmath.structures.RealBuffer @Suppress("OVERRIDE_BY_INLINE") @@ -22,9 +19,9 @@ public object RealMatrixContext : MatrixContext> { produce(rowNum, colNum) { i, j -> get(i, j) } } - public fun one(rows: Int, columns: Int): FeaturedMatrix = VirtualMatrix(rows, columns, DiagonalFeature) { i, j -> + public fun one(rows: Int, columns: Int): Matrix = VirtualMatrix(rows, columns) { i, j -> if (i == j) 1.0 else 0.0 - } + } + DiagonalFeature public override infix fun Matrix.dot(other: Matrix): BufferMatrix { require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } @@ -69,16 +66,3 @@ public object RealMatrixContext : MatrixContext> { * Partially optimized real-valued matrix */ public val MatrixContext.Companion.real: RealMatrixContext get() = RealMatrixContext - -public fun RealMatrixContext.solveWithLUP(a: Matrix, b: Matrix): FeaturedMatrix { - // Use existing decomposition if it is provided by matrix - val bufferFactory: MutableBufferFactory = MutableBuffer.Companion::real - val decomposition = a.getFeature() ?: lup(bufferFactory, RealField, a) { it < 1e-11 } - return decomposition.solveWithLUP(bufferFactory, b) -} - -/** - * Inverses a square matrix using LUP decomposition. Non square matrix will throw a error. - */ -public fun RealMatrixContext.inverseWithLUP(matrix: Matrix): FeaturedMatrix = - solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum)) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/VirtualMatrix.kt index e0a1d0026..0269a64d1 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/VirtualMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/VirtualMatrix.kt @@ -5,31 +5,16 @@ import kscience.kmath.structures.Matrix public class VirtualMatrix( override val rowNum: Int, override val colNum: Int, - override val features: Set = emptySet(), public val generator: (i: Int, j: Int) -> T -) : FeaturedMatrix { - public constructor( - rowNum: Int, - colNum: Int, - vararg features: MatrixFeature, - generator: (i: Int, j: Int) -> T - ) : this( - rowNum, - colNum, - setOf(*features), - generator - ) +) : Matrix { override val shape: IntArray get() = intArrayOf(rowNum, colNum) override operator fun get(i: Int, j: Int): T = generator(i, j) - override fun suggestFeature(vararg features: MatrixFeature): VirtualMatrix = - VirtualMatrix(rowNum, colNum, this.features + features, generator) - override fun equals(other: Any?): Boolean { if (this === other) return true - if (other !is FeaturedMatrix<*>) return false + if (other !is Matrix<*>) return false if (rowNum != other.rowNum) return false if (colNum != other.colNum) return false @@ -40,21 +25,9 @@ public class VirtualMatrix( override fun hashCode(): Int { var result = rowNum result = 31 * result + colNum - result = 31 * result + features.hashCode() result = 31 * result + generator.hashCode() return result } - public companion object { - /** - * Wrap a matrix adding additional features to it - */ - public fun wrap(matrix: Matrix, vararg features: MatrixFeature): FeaturedMatrix { - return if (matrix is VirtualMatrix) - VirtualMatrix(matrix.rowNum, matrix.colNum, matrix.features + features, matrix.generator) - else - VirtualMatrix(matrix.rowNum, matrix.colNum, matrix.features + features) { i, j -> matrix[i, j] } - } - } } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/numbers.kt index de3818aa6..0440d74e8 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/numbers.kt @@ -179,13 +179,15 @@ public 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") -public object IntRing : Ring, Norm { +public object IntRing : Ring, Norm, NumericAlgebra { public override val zero: Int get() = 0 public override val one: Int get() = 1 + override fun number(value: Number): Int = value.toInt() + public override inline fun add(a: Int, b: Int): Int = a + b public override inline fun multiply(a: Int, k: Number): Int = k.toInt() * a @@ -203,13 +205,15 @@ public 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") -public object ShortRing : Ring, Norm { +public object ShortRing : Ring, Norm, NumericAlgebra { public override val zero: Short get() = 0 public override val one: Short get() = 1 + override fun number(value: Number): Short = value.toShort() + public override inline fun add(a: Short, b: Short): Short = (a + b).toShort() public override inline fun multiply(a: Short, k: Number): Short = (a * k.toShort()).toShort() @@ -227,13 +231,15 @@ public 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") -public object ByteRing : Ring, Norm { +public object ByteRing : Ring, Norm, NumericAlgebra { public override val zero: Byte get() = 0 public override val one: Byte get() = 1 + override fun number(value: Number): Byte = value.toByte() + public override inline fun add(a: Byte, b: Byte): Byte = (a + b).toByte() public override inline fun multiply(a: Byte, k: Number): Byte = (a * k.toByte()).toByte() @@ -251,13 +257,15 @@ public 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") -public object LongRing : Ring, Norm { +public object LongRing : Ring, Norm, NumericAlgebra { public override val zero: Long get() = 0L public override val one: Long get() = 1L + override fun number(value: Number): Long = value.toLong() + public override inline fun add(a: Long, b: Long): Long = a + b public override inline fun multiply(a: Long, k: Number): Long = a * k.toLong() 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 5c5d28882..64e723581 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt @@ -1,5 +1,6 @@ package kscience.kmath.structures +import kscience.kmath.misc.UnstableKMathAPI import kotlin.jvm.JvmName import kotlin.native.concurrent.ThreadLocal import kotlin.reflect.KClass @@ -42,6 +43,13 @@ public interface NDStructure { public override fun equals(other: Any?): Boolean public override fun hashCode(): Int + /** + * Feature is additional property or hint that does not directly affect the structure, but could in some cases help + * optimize operations and performance. If the feature is not present, null is defined. + */ + @UnstableKMathAPI + public fun getFeature(type: KClass): T? = null + public companion object { /** * Indicates whether some [NDStructure] is equal to another one. @@ -121,6 +129,9 @@ public interface NDStructure { */ public operator fun NDStructure.get(vararg index: Int): T = get(index) +@UnstableKMathAPI +public inline fun NDStructure<*>.getFeature(): T? = getFeature(T::class) + /** * Represents mutable [NDStructure]. */ diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Structure2D.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Structure2D.kt index bac7d3389..d20e9e53b 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Structure2D.kt @@ -9,12 +9,14 @@ public interface Structure2D : NDStructure { /** * The number of rows in this structure. */ - public val rowNum: Int get() = shape[0] + public val rowNum: Int /** * The number of columns in this structure. */ - public val colNum: Int get() = shape[1] + public val colNum: Int + + public override val shape: IntArray get() = intArrayOf(rowNum, colNum) /** * The buffer of rows of this structure. It gets elements from the structure dynamically. @@ -56,6 +58,9 @@ public interface Structure2D : NDStructure { private inline class Structure2DWrapper(val structure: NDStructure) : Structure2D { override val shape: IntArray get() = structure.shape + override val rowNum: Int get() = shape[0] + override val colNum: Int get() = shape[1] + override operator fun get(i: Int, j: Int): T = structure[i, j] override fun elements(): Sequence> = structure.elements() diff --git a/kmath-dimensions/src/commonMain/kotlin/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/kscience/kmath/dimensions/Wrappers.kt index 0422d11b2..0244eae7f 100644 --- a/kmath-dimensions/src/commonMain/kotlin/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/kscience/kmath/dimensions/Wrappers.kt @@ -40,6 +40,8 @@ public inline class DMatrixWrapper( private val structure: Structure2D, ) : DMatrix { override val shape: IntArray get() = structure.shape + override val rowNum: Int get() = shape[0] + override val colNum: Int get() = shape[1] override operator fun get(i: Int, j: Int): T = structure[i, j] } @@ -147,6 +149,7 @@ public inline fun DMatrixContext.one(): DMatrix< if (i == j) 1.0 else 0.0 } -public inline fun DMatrixContext.zero(): DMatrix = produce { _, _ -> - 0.0 -} \ No newline at end of file +public inline fun DMatrixContext.zero(): DMatrix = + produce { _, _ -> + 0.0 + } \ No newline at end of file diff --git a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt index a7d571b58..1c2ded447 100644 --- a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt +++ b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt @@ -1,10 +1,13 @@ package kscience.kmath.ejml import kscience.kmath.linear.* -import kscience.kmath.structures.NDStructure +import kscience.kmath.misc.UnstableKMathAPI +import kscience.kmath.structures.Matrix import kscience.kmath.structures.RealBuffer import org.ejml.dense.row.factory.DecompositionFactory_DDRM import org.ejml.simple.SimpleMatrix +import kotlin.reflect.KClass +import kotlin.reflect.cast /** * Represents featured matrix over EJML [SimpleMatrix]. @@ -12,85 +15,65 @@ import org.ejml.simple.SimpleMatrix * @property origin the underlying [SimpleMatrix]. * @author Iaroslav Postovalov */ -public class EjmlMatrix( +public inline class EjmlMatrix( public val origin: SimpleMatrix, - features: Set = emptySet() -) : FeaturedMatrix { - public override val rowNum: Int - get() = origin.numRows() +) : Matrix { + public override val rowNum: Int get() = origin.numRows() - public override val colNum: Int - get() = origin.numCols() + public override val colNum: Int get() = origin.numCols() - public override val shape: IntArray by lazy { intArrayOf(rowNum, colNum) } - - public override val features: Set = hashSetOf( - object : InverseMatrixFeature { - override val inverse: FeaturedMatrix by lazy { EjmlMatrix(origin.invert()) } - }, - - object : DeterminantFeature { + @UnstableKMathAPI + override fun getFeature(type: KClass): T? = when (type) { + InverseMatrixFeature::class -> object : InverseMatrixFeature { + override val inverse: Matrix by lazy { EjmlMatrix(origin.invert()) } + } + DeterminantFeature::class -> object : DeterminantFeature { override val determinant: Double by lazy(origin::determinant) - }, - - object : SingularValueDecompositionFeature { + } + SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { private val svd by lazy { DecompositionFactory_DDRM.svd(origin.numRows(), origin.numCols(), true, true, false) .apply { decompose(origin.ddrm.copy()) } } - override val u: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(svd.getU(null, false))) } - override val s: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(svd.getW(null))) } - override val v: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(svd.getV(null, false))) } + override val u: Matrix by lazy { EjmlMatrix(SimpleMatrix(svd.getU(null, false))) } + override val s: Matrix by lazy { EjmlMatrix(SimpleMatrix(svd.getW(null))) } + override val v: Matrix by lazy { EjmlMatrix(SimpleMatrix(svd.getV(null, false))) } override val singularValues: Point by lazy { RealBuffer(svd.singularValues) } - }, - - object : QRDecompositionFeature { + } + QRDecompositionFeature::class -> object : QRDecompositionFeature { private val qr by lazy { DecompositionFactory_DDRM.qr().apply { decompose(origin.ddrm.copy()) } } - override val q: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(qr.getQ(null, false))) } - override val r: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(qr.getR(null, false))) } - }, - - object : CholeskyDecompositionFeature { - override val l: FeaturedMatrix by lazy { + override val q: Matrix by lazy { EjmlMatrix(SimpleMatrix(qr.getQ(null, false))) } + override val r: Matrix by lazy { EjmlMatrix(SimpleMatrix(qr.getR(null, false))) } + } + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { val cholesky = DecompositionFactory_DDRM.chol(rowNum, true).apply { decompose(origin.ddrm.copy()) } - EjmlMatrix(SimpleMatrix(cholesky.getT(null)), setOf(LFeature)) + EjmlMatrix(SimpleMatrix(cholesky.getT(null))) + LFeature } - }, - - object : LupDecompositionFeature { + } + LupDecompositionFeature::class -> object : LupDecompositionFeature { private val lup by lazy { DecompositionFactory_DDRM.lu(origin.numRows(), origin.numCols()).apply { decompose(origin.ddrm.copy()) } } - override val l: FeaturedMatrix by lazy { - EjmlMatrix(SimpleMatrix(lup.getLower(null)), setOf(LFeature)) + override val l: Matrix by lazy { + EjmlMatrix(SimpleMatrix(lup.getLower(null))) + LFeature } - override val u: FeaturedMatrix by lazy { - EjmlMatrix(SimpleMatrix(lup.getUpper(null)), setOf(UFeature)) + override val u: Matrix by lazy { + EjmlMatrix(SimpleMatrix(lup.getUpper(null))) + UFeature } - override val p: FeaturedMatrix by lazy { EjmlMatrix(SimpleMatrix(lup.getRowPivot(null))) } - }, - ) union features - - public override fun suggestFeature(vararg features: MatrixFeature): EjmlMatrix = - EjmlMatrix(origin, this.features + features) + override val p: Matrix by lazy { EjmlMatrix(SimpleMatrix(lup.getRowPivot(null))) } + } + else -> null + }?.let{type.cast(it)} public override operator fun get(i: Int, j: Int): Double = origin[i, j] - - public override fun equals(other: Any?): Boolean { - if (other is EjmlMatrix) return origin.isIdentical(other.origin, 0.0) - return NDStructure.equals(this, other as? NDStructure<*> ?: return false) - } - - public override fun hashCode(): Int = origin.hashCode() - - public override fun toString(): String = "EjmlMatrix($origin)" } diff --git a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt index c8789a4a7..7198bbd0d 100644 --- a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt +++ b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt @@ -2,23 +2,29 @@ package kscience.kmath.ejml import kscience.kmath.linear.InverseMatrixFeature import kscience.kmath.linear.MatrixContext +import kscience.kmath.linear.MatrixWrapper import kscience.kmath.linear.Point -import kscience.kmath.linear.getFeature +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.structures.Matrix +import kscience.kmath.structures.getFeature import org.ejml.simple.SimpleMatrix -/** - * Converts this matrix to EJML one. - */ -public fun Matrix.toEjml(): EjmlMatrix = - if (this is EjmlMatrix) this else EjmlMatrixContext.produce(rowNum, colNum) { i, j -> get(i, j) } - /** * Represents context of basic operations operating with [EjmlMatrix]. * * @author Iaroslav Postovalov */ public object EjmlMatrixContext : MatrixContext { + + /** + * Converts this matrix to EJML one. + */ + public fun Matrix.toEjml(): EjmlMatrix = when { + this is EjmlMatrix -> this + this is MatrixWrapper && matrix is EjmlMatrix -> matrix as EjmlMatrix + else -> produce(rowNum, colNum) { i, j -> get(i, j) } + } + /** * Converts this vector to EJML one. */ @@ -80,6 +86,7 @@ public fun EjmlMatrixContext.solve(a: Matrix, b: Matrix): EjmlMa public fun EjmlMatrixContext.solve(a: Matrix, b: Point): EjmlVector = EjmlVector(a.toEjml().origin.solve(b.toEjml().origin)) +@OptIn(UnstableKMathAPI::class) public fun EjmlMatrix.inverted(): EjmlMatrix = getFeature>()!!.inverse as EjmlMatrix public fun EjmlMatrixContext.inverse(matrix: Matrix): Matrix = matrix.toEjml().inverted() \ No newline at end of file diff --git a/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt index 70b82a3cb..30d146779 100644 --- a/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt +++ b/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt @@ -3,7 +3,8 @@ package kscience.kmath.ejml import kscience.kmath.linear.DeterminantFeature import kscience.kmath.linear.LupDecompositionFeature import kscience.kmath.linear.MatrixFeature -import kscience.kmath.linear.getFeature +import kscience.kmath.linear.plus +import kscience.kmath.structures.getFeature import org.ejml.dense.row.factory.DecompositionFactory_DDRM import org.ejml.simple.SimpleMatrix import kotlin.random.Random @@ -58,7 +59,7 @@ internal class EjmlMatrixTest { @Test fun suggestFeature() { - assertNotNull(EjmlMatrix(randomMatrix).suggestFeature(SomeFeature).getFeature()) + assertNotNull((EjmlMatrix(randomMatrix) + SomeFeature).getFeature()) } @Test diff --git a/kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt b/kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt index 772abfbed..274030aff 100644 --- a/kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt +++ b/kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt @@ -1,8 +1,12 @@ package kscience.kmath.real -import kscience.kmath.linear.* +import kscience.kmath.linear.MatrixContext +import kscience.kmath.linear.VirtualMatrix +import kscience.kmath.linear.inverseWithLUP +import kscience.kmath.linear.real import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.structures.Buffer +import kscience.kmath.structures.Matrix import kscience.kmath.structures.RealBuffer import kscience.kmath.structures.asIterable import kotlin.math.pow @@ -19,7 +23,7 @@ import kotlin.math.pow * Functions that help create a real (Double) matrix */ -public typealias RealMatrix = FeaturedMatrix +public typealias RealMatrix = Matrix public fun realMatrix(rowNum: Int, colNum: Int, initializer: (i: Int, j: Int) -> Double): RealMatrix = MatrixContext.real.produce(rowNum, colNum, initializer) diff --git a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/RealMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/RealMatrixTest.kt index 5c33b76a9..a89f99b3c 100644 --- a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/RealMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/RealMatrixTest.kt @@ -1,6 +1,5 @@ package kaceince.kmath.real -import kscience.kmath.linear.VirtualMatrix import kscience.kmath.linear.build import kscience.kmath.real.* import kscience.kmath.structures.Matrix @@ -42,7 +41,7 @@ internal class RealMatrixTest { 1.0, 0.0, 0.0, 0.0, 1.0, 2.0 ) - assertEquals(VirtualMatrix.wrap(matrix2), matrix1.repeatStackVertical(3)) + assertEquals(matrix2, matrix1.repeatStackVertical(3)) } @Test From d0c9d97706fa21584af1e99984a2763810bcd4f9 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 19 Jan 2021 22:24:42 +0300 Subject: [PATCH 51/55] Minor optimization for RealNDAlgebra --- .../ast/ExpressionsInterpretersBenchmark.kt | 4 +- .../kscience/kmath/benchmarks/DotBenchmark.kt | 20 ++++----- .../kmath/benchmarks/LargeNDBenchmark.kt | 25 ----------- .../benchmarks/LinearAlgebraBenchmark.kt | 8 +--- .../FunctionalExpressionAlgebra.kt | 5 ++- .../kscience/kmath/linear/LupDecomposition.kt | 1 + .../kscience/kmath/operations/Complex.kt | 2 + .../kscience/kmath/structures/RealNDField.kt | 41 +++++++++---------- .../kscience/kmath/linear/MatrixTest.kt | 1 + .../kmath/structures/NumberNDFieldTest.kt | 1 + .../kscience/dimensions/DMatrixContextTest.kt | 1 + 11 files changed, 42 insertions(+), 67 deletions(-) delete mode 100644 examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt index 6acaca84d..c5edcdedf 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt @@ -28,7 +28,7 @@ internal class ExpressionsInterpretersBenchmark { @Benchmark fun mstExpression() { val expr = algebra.mstInField { - symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0) + symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0 } invokeAndSum(expr) @@ -37,7 +37,7 @@ internal class ExpressionsInterpretersBenchmark { @Benchmark fun asmExpression() { val expr = algebra.mstInField { - symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0) + symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0 }.compile() invokeAndSum(expr) diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt index 8823e86db..5c59afaee 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt @@ -2,9 +2,8 @@ package kscience.kmath.benchmarks import kotlinx.benchmark.Benchmark import kscience.kmath.commons.linear.CMMatrixContext -import kscience.kmath.commons.linear.toCM import kscience.kmath.ejml.EjmlMatrixContext -import kscience.kmath.ejml.toEjml + import kscience.kmath.linear.BufferMatrixContext import kscience.kmath.linear.RealMatrixContext import kscience.kmath.linear.real @@ -26,11 +25,11 @@ class DotBenchmark { val matrix1 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } val matrix2 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - val cmMatrix1 = matrix1.toCM() - val cmMatrix2 = matrix2.toCM() + val cmMatrix1 = CMMatrixContext { matrix1.toCM() } + val cmMatrix2 = CMMatrixContext { matrix2.toCM() } - val ejmlMatrix1 = matrix1.toEjml() - val ejmlMatrix2 = matrix2.toEjml() + val ejmlMatrix1 = EjmlMatrixContext { matrix1.toEjml() } + val ejmlMatrix2 = EjmlMatrixContext { matrix2.toEjml() } } @Benchmark @@ -49,22 +48,23 @@ class DotBenchmark { @Benchmark fun ejmlMultiplicationwithConversion() { - val ejmlMatrix1 = matrix1.toEjml() - val ejmlMatrix2 = matrix2.toEjml() EjmlMatrixContext { + val ejmlMatrix1 = matrix1.toEjml() + val ejmlMatrix2 = matrix2.toEjml() + ejmlMatrix1 dot ejmlMatrix2 } } @Benchmark fun bufferedMultiplication() { - BufferMatrixContext(RealField, Buffer.Companion::real).invoke{ + BufferMatrixContext(RealField, Buffer.Companion::real).invoke { matrix1 dot matrix2 } } @Benchmark - fun realMultiplication(){ + fun realMultiplication() { RealMatrixContext { matrix1 dot matrix2 } diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt deleted file mode 100644 index 395fde619..000000000 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt +++ /dev/null @@ -1,25 +0,0 @@ -package kscience.kmath.benchmarks - -import kscience.kmath.structures.NDField -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State -import org.openjdk.jmh.infra.Blackhole -import kotlin.random.Random - -@State(Scope.Benchmark) -class LargeNDBenchmark { - val arraySize = 10000 - val RANDOM = Random(222) - val src1 = DoubleArray(arraySize) { RANDOM.nextDouble() } - val src2 = DoubleArray(arraySize) { RANDOM.nextDouble() } - val field = NDField.real(arraySize) - val kmathArray1 = field.produce { (a) -> src1[a] } - val kmathArray2 = field.produce { (a) -> src2[a] } - - @Benchmark - fun test10000(bh: Blackhole) { - bh.consume(field.add(kmathArray1, kmathArray2)) - } - -} \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt index ec8714617..5ff43ef80 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt @@ -5,10 +5,8 @@ import kotlinx.benchmark.Benchmark import kscience.kmath.commons.linear.CMMatrixContext import kscience.kmath.commons.linear.CMMatrixContext.dot import kscience.kmath.commons.linear.inverse -import kscience.kmath.commons.linear.toCM import kscience.kmath.ejml.EjmlMatrixContext import kscience.kmath.ejml.inverse -import kscience.kmath.ejml.toEjml import kscience.kmath.operations.invoke import kscience.kmath.structures.Matrix import org.openjdk.jmh.annotations.Scope @@ -35,16 +33,14 @@ class LinearAlgebraBenchmark { @Benchmark fun cmLUPInversion() { CMMatrixContext { - val cm = matrix.toCM() //avoid overhead on conversion - inverse(cm) + inverse(matrix) } } @Benchmark fun ejmlInverse() { EjmlMatrixContext { - val km = matrix.toEjml() //avoid overhead on conversion - inverse(km) + inverse(matrix) } } } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 880a4e34c..1a3668855 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -95,8 +95,9 @@ public open class FunctionalExpressionRing>( super.binaryOperationFunction(operation) } -public open class FunctionalExpressionField>(algebra: A) : - FunctionalExpressionRing(algebra), Field> { +public open class FunctionalExpressionField>( + algebra: A, +) : FunctionalExpressionRing(algebra), Field> { /** * Builds an Expression of division an expression by another one. */ diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt index f4f998da2..5cf7c8f70 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt @@ -224,6 +224,7 @@ public inline fun , F : Field> GenericMatrixContext ): Matrix = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) +@OptIn(UnstableKMathAPI::class) public fun RealMatrixContext.solveWithLUP(a: Matrix, b: Matrix): Matrix { // Use existing decomposition if it is provided by matrix val bufferFactory: MutableBufferFactory = MutableBuffer.Companion::real 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 5695e6696..c6409c015 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt @@ -3,6 +3,7 @@ package kscience.kmath.operations import kscience.kmath.memory.MemoryReader import kscience.kmath.memory.MemorySpec import kscience.kmath.memory.MemoryWriter +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.structures.Buffer import kscience.kmath.structures.MemoryBuffer import kscience.kmath.structures.MutableBuffer @@ -41,6 +42,7 @@ private val PI_DIV_2 = Complex(PI / 2, 0) /** * A field of [Complex]. */ +@OptIn(UnstableKMathAPI::class) public object ComplexField : ExtendedField, Norm, RingWithNumbers { override val zero: Complex = 0.0.toComplex() override val one: Complex = 1.0.toComplex() diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt index 3eb1dc4ca..60e6de440 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt @@ -11,7 +11,7 @@ public typealias RealNDElement = BufferedNDFieldElement public class RealNDField(override val shape: IntArray) : BufferedNDField, ExtendedNDField>, - RingWithNumbers>{ + RingWithNumbers> { override val strides: Strides = DefaultStrides(shape) @@ -24,35 +24,31 @@ public class RealNDField(override val shape: IntArray) : return produce { d } } - private inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer = - RealBuffer(DoubleArray(size) { initializer(it) }) - - /** - * Inline transform an NDStructure to - */ - override fun map( + @Suppress("OVERRIDE_BY_INLINE") + override inline fun map( arg: NDBuffer, - transform: RealField.(Double) -> Double + transform: RealField.(Double) -> Double, ): RealNDElement { check(arg) - val array = buildBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) } + val array = RealBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) } return BufferedNDFieldElement(this, array) } - override fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement { - val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } + @Suppress("OVERRIDE_BY_INLINE") + override inline fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement { + val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } return BufferedNDFieldElement(this, array) } - override fun mapIndexed( + @Suppress("OVERRIDE_BY_INLINE") + override inline fun mapIndexed( arg: NDBuffer, - transform: RealField.(index: IntArray, Double) -> Double + transform: RealField.(index: IntArray, Double) -> Double, ): RealNDElement { check(arg) - return BufferedNDFieldElement( this, - buildBuffer(arg.strides.linearSize) { offset -> + RealBuffer(arg.strides.linearSize) { offset -> elementContext.transform( arg.strides.index(offset), arg.buffer[offset] @@ -60,16 +56,17 @@ public class RealNDField(override val shape: IntArray) : }) } - override fun combine( + @Suppress("OVERRIDE_BY_INLINE") + override inline fun combine( a: NDBuffer, b: NDBuffer, - transform: RealField.(Double, Double) -> Double + transform: RealField.(Double, Double) -> Double, ): RealNDElement { check(a, b) - return BufferedNDFieldElement( - this, - buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) } - ) + val buffer = RealBuffer(strides.linearSize) { offset -> + elementContext.transform(a.buffer[offset], b.buffer[offset]) + } + return BufferedNDFieldElement(this, buffer) } override fun NDBuffer.toElement(): FieldElement, *, out BufferedNDField> = diff --git a/kmath-core/src/commonTest/kotlin/kscience/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/kscience/kmath/linear/MatrixTest.kt index 0a582e339..d7755dcb5 100644 --- a/kmath-core/src/commonTest/kotlin/kscience/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/kscience/kmath/linear/MatrixTest.kt @@ -7,6 +7,7 @@ import kscience.kmath.structures.as2D import kotlin.test.Test import kotlin.test.assertEquals +@Suppress("UNUSED_VARIABLE") class MatrixTest { @Test fun testTranspose() { diff --git a/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NumberNDFieldTest.kt index f5e008ef3..22a0d3629 100644 --- a/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NumberNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NumberNDFieldTest.kt @@ -8,6 +8,7 @@ import kotlin.math.pow import kotlin.test.Test import kotlin.test.assertEquals +@Suppress("UNUSED_VARIABLE") class NumberNDFieldTest { val array1: RealNDElement = real2D(3, 3) { i, j -> (i + j).toDouble() } val array2: RealNDElement = real2D(3, 3) { i, j -> (i - j).toDouble() } diff --git a/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt index 5b330fcce..b9193d4dd 100644 --- a/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt +++ b/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt @@ -6,6 +6,7 @@ import kscience.kmath.dimensions.DMatrixContext import kscience.kmath.dimensions.one import kotlin.test.Test +@Suppress("UNUSED_VARIABLE") internal class DMatrixContextTest { @Test fun testDimensionSafeMatrix() { From 1c7bd05c584528cf569aa5f7f537c056e89e4a6e Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 19 Jan 2021 22:48:43 +0300 Subject: [PATCH 52/55] Add proper equality check for EJML matrices --- .../kscience/kmath/linear/BufferMatrix.kt | 2 +- .../kscience/kmath/structures/NDStructure.kt | 4 ++-- .../kmath/structures/LazyNDStructure.kt | 2 +- .../kotlin/kscience/kmath/ejml/EjmlMatrix.kt | 19 +++++++++++++++---- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt index 80460baca..a74d948fc 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/BufferMatrix.kt @@ -43,7 +43,7 @@ public class BufferMatrix( if (this === other) return true return when (other) { - is NDStructure<*> -> NDStructure.equals(this, other) + is NDStructure<*> -> NDStructure.contentEquals(this, other) else -> false } } 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 64e723581..e7d89ca7e 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt @@ -54,7 +54,7 @@ public interface NDStructure { /** * Indicates whether some [NDStructure] is equal to another one. */ - public fun equals(st1: NDStructure<*>, st2: NDStructure<*>): Boolean { + public fun contentEquals(st1: NDStructure<*>, st2: NDStructure<*>): Boolean { if (st1 === st2) return true // fast comparison of buffers if possible @@ -275,7 +275,7 @@ public abstract class NDBuffer : NDStructure { override fun elements(): Sequence> = strides.indices().map { it to this[it] } override fun equals(other: Any?): Boolean { - return NDStructure.equals(this, other as? NDStructure<*> ?: return false) + return NDStructure.contentEquals(this, other as? NDStructure<*> ?: return false) } override fun hashCode(): Int { diff --git a/kmath-coroutines/src/jvmMain/kotlin/kscience/kmath/structures/LazyNDStructure.kt b/kmath-coroutines/src/jvmMain/kotlin/kscience/kmath/structures/LazyNDStructure.kt index bb0d19c23..7aa746797 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/kscience/kmath/structures/LazyNDStructure.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/kscience/kmath/structures/LazyNDStructure.kt @@ -24,7 +24,7 @@ public class LazyNDStructure( } public override fun equals(other: Any?): Boolean { - return NDStructure.equals(this, other as? NDStructure<*> ?: return false) + return NDStructure.contentEquals(this, other as? NDStructure<*> ?: return false) } public override fun hashCode(): Int { diff --git a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt index 1c2ded447..82a5399fd 100644 --- a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt +++ b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrix.kt @@ -3,6 +3,7 @@ package kscience.kmath.ejml import kscience.kmath.linear.* import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.structures.Matrix +import kscience.kmath.structures.NDStructure import kscience.kmath.structures.RealBuffer import org.ejml.dense.row.factory.DecompositionFactory_DDRM import org.ejml.simple.SimpleMatrix @@ -15,7 +16,7 @@ import kotlin.reflect.cast * @property origin the underlying [SimpleMatrix]. * @author Iaroslav Postovalov */ -public inline class EjmlMatrix( +public class EjmlMatrix( public val origin: SimpleMatrix, ) : Matrix { public override val rowNum: Int get() = origin.numRows() @@ -49,7 +50,7 @@ public inline class EjmlMatrix( override val q: Matrix by lazy { EjmlMatrix(SimpleMatrix(qr.getQ(null, false))) } override val r: Matrix by lazy { EjmlMatrix(SimpleMatrix(qr.getR(null, false))) } } - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { override val l: Matrix by lazy { val cholesky = DecompositionFactory_DDRM.chol(rowNum, true).apply { decompose(origin.ddrm.copy()) } @@ -57,7 +58,7 @@ public inline class EjmlMatrix( EjmlMatrix(SimpleMatrix(cholesky.getT(null))) + LFeature } } - LupDecompositionFeature::class -> object : LupDecompositionFeature { + LupDecompositionFeature::class -> object : LupDecompositionFeature { private val lup by lazy { DecompositionFactory_DDRM.lu(origin.numRows(), origin.numCols()).apply { decompose(origin.ddrm.copy()) } } @@ -73,7 +74,17 @@ public inline class EjmlMatrix( override val p: Matrix by lazy { EjmlMatrix(SimpleMatrix(lup.getRowPivot(null))) } } else -> null - }?.let{type.cast(it)} + }?.let { type.cast(it) } public override operator fun get(i: Int, j: Int): Double = origin[i, j] + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Matrix<*>) return false + return NDStructure.contentEquals(this, other) + } + + override fun hashCode(): Int = origin.hashCode() + + } From d00e7434a4e14a5fbc6039f823b02fffd7b86d47 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 20 Jan 2021 15:07:39 +0300 Subject: [PATCH 53/55] Fix for #193 --- .../src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt index bbe9c1195..1db905bf2 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt @@ -25,6 +25,7 @@ public class MatrixWrapper( */ @UnstableKMathAPI override fun getFeature(type: KClass): T? = type.safeCast(features.find { type.isInstance(it) }) + ?: matrix.getFeature(type) override fun equals(other: Any?): Boolean = matrix == other override fun hashCode(): Int = matrix.hashCode() From 881b85a1d9dabc30c5d5baa8821d170800e64700 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 20 Jan 2021 15:32:55 +0300 Subject: [PATCH 54/55] Add `origin` (optin) extension property to expose MatrixWrapper content --- .../kscience/kmath/commons/linear/CMMatrix.kt | 8 +++--- .../kscience/kmath/linear/MatrixWrapper.kt | 25 ++++++++++++------- .../kscience/kmath/ejml/EjmlMatrixContext.kt | 8 +++--- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt index 48b6e0ef1..850446afa 100644 --- a/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt +++ b/kmath-commons/src/main/kotlin/kscience/kmath/commons/linear/CMMatrix.kt @@ -2,8 +2,8 @@ package kscience.kmath.commons.linear import kscience.kmath.linear.DiagonalFeature import kscience.kmath.linear.MatrixContext -import kscience.kmath.linear.MatrixWrapper import kscience.kmath.linear.Point +import kscience.kmath.linear.origin import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.structures.Matrix import org.apache.commons.math3.linear.* @@ -47,9 +47,9 @@ public object CMMatrixContext : MatrixContext { return CMMatrix(Array2DRowRealMatrix(array)) } - public fun Matrix.toCM(): CMMatrix = when { - this is CMMatrix -> this - this is MatrixWrapper && matrix is CMMatrix -> matrix as CMMatrix + @OptIn(UnstableKMathAPI::class) + public fun Matrix.toCM(): CMMatrix = when (val matrix = origin) { + is CMMatrix -> matrix else -> { //TODO add feature analysis val array = Array(rowNum) { i -> DoubleArray(colNum) { j -> get(i, j) } } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt index 1db905bf2..362db1fe7 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/MatrixWrapper.kt @@ -15,30 +15,37 @@ import kotlin.reflect.safeCast * * @param T the type of items. */ -public class MatrixWrapper( - public val matrix: Matrix, +public class MatrixWrapper internal constructor( + public val origin: Matrix, public val features: Set, -) : Matrix by matrix { +) : Matrix by origin { /** * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria */ @UnstableKMathAPI override fun getFeature(type: KClass): T? = type.safeCast(features.find { type.isInstance(it) }) - ?: matrix.getFeature(type) + ?: origin.getFeature(type) - override fun equals(other: Any?): Boolean = matrix == other - override fun hashCode(): Int = matrix.hashCode() + override fun equals(other: Any?): Boolean = origin == other + override fun hashCode(): Int = origin.hashCode() override fun toString(): String { - return "MatrixWrapper(matrix=$matrix, features=$features)" + return "MatrixWrapper(matrix=$origin, features=$features)" } } +/** + * Return the original matrix. If this is a wrapper, return its origin. If not, this matrix. + * Origin does not necessary store all features. + */ +@UnstableKMathAPI +public val Matrix.origin: Matrix get() = (this as? MatrixWrapper)?.origin ?: this + /** * Add a single feature to a [Matrix] */ public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixWrapper = if (this is MatrixWrapper) { - MatrixWrapper(matrix, features + newFeature) + MatrixWrapper(origin, features + newFeature) } else { MatrixWrapper(this, setOf(newFeature)) } @@ -48,7 +55,7 @@ public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixW */ public operator fun Matrix.plus(newFeatures: Collection): MatrixWrapper = if (this is MatrixWrapper) { - MatrixWrapper(matrix, features + newFeatures) + MatrixWrapper(origin, features + newFeatures) } else { MatrixWrapper(this, newFeatures.toSet()) } diff --git a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt index 7198bbd0d..8184d0110 100644 --- a/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt +++ b/kmath-ejml/src/main/kotlin/kscience/kmath/ejml/EjmlMatrixContext.kt @@ -2,8 +2,8 @@ package kscience.kmath.ejml import kscience.kmath.linear.InverseMatrixFeature import kscience.kmath.linear.MatrixContext -import kscience.kmath.linear.MatrixWrapper import kscience.kmath.linear.Point +import kscience.kmath.linear.origin import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.structures.Matrix import kscience.kmath.structures.getFeature @@ -19,9 +19,9 @@ public object EjmlMatrixContext : MatrixContext { /** * Converts this matrix to EJML one. */ - public fun Matrix.toEjml(): EjmlMatrix = when { - this is EjmlMatrix -> this - this is MatrixWrapper && matrix is EjmlMatrix -> matrix as EjmlMatrix + @OptIn(UnstableKMathAPI::class) + public fun Matrix.toEjml(): EjmlMatrix = when (val matrix = origin) { + is EjmlMatrix -> matrix else -> produce(rowNum, colNum) { i, j -> get(i, j) } } From d10ae66e580f7d87410d44cc082b5adb79554769 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 20 Jan 2021 17:08:29 +0300 Subject: [PATCH 55/55] Deploy fixes for 0.2.0-dev-5 --- .../src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt | 2 +- .../src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt | 3 +++ .../src/jvmTest/kotlin/kscience/kmath/stat/MCScopeTest.kt | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt index 2bafd377e..e7eb2770d 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt @@ -92,7 +92,7 @@ public interface Algebra { * Call a block with an [Algebra] as receiver. */ // TODO add contract when KT-32313 is fixed -public inline operator fun , R> A.invoke(block: A.() -> R): R = block() +public inline operator fun , R> A.invoke(block: A.() -> R): R = run(block) /** * Represents "semispace", i.e. algebraic structure with associative binary operation called "addition" as well as diff --git a/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt index 30d146779..455b52d9d 100644 --- a/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt +++ b/kmath-ejml/src/test/kotlin/kscience/kmath/ejml/EjmlMatrixTest.kt @@ -4,6 +4,7 @@ import kscience.kmath.linear.DeterminantFeature import kscience.kmath.linear.LupDecompositionFeature import kscience.kmath.linear.MatrixFeature import kscience.kmath.linear.plus +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.structures.getFeature import org.ejml.dense.row.factory.DecompositionFactory_DDRM import org.ejml.simple.SimpleMatrix @@ -39,6 +40,7 @@ internal class EjmlMatrixTest { assertEquals(listOf(m.numRows(), m.numCols()), w.shape.toList()) } + @OptIn(UnstableKMathAPI::class) @Test fun features() { val m = randomMatrix @@ -57,6 +59,7 @@ internal class EjmlMatrixTest { private object SomeFeature : MatrixFeature {} + @OptIn(UnstableKMathAPI::class) @Test fun suggestFeature() { assertNotNull((EjmlMatrix(randomMatrix) + SomeFeature).getFeature()) diff --git a/kmath-stat/src/jvmTest/kotlin/kscience/kmath/stat/MCScopeTest.kt b/kmath-stat/src/jvmTest/kotlin/kscience/kmath/stat/MCScopeTest.kt index c2304070f..4e29e6105 100644 --- a/kmath-stat/src/jvmTest/kotlin/kscience/kmath/stat/MCScopeTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/kscience/kmath/stat/MCScopeTest.kt @@ -62,6 +62,7 @@ class MCScopeTest { } + @OptIn(ObsoleteCoroutinesApi::class) fun compareResult(test: ATest) { val res1 = runBlocking(Dispatchers.Default) { test() } val res2 = runBlocking(newSingleThreadContext("test")) { test() }