From 1fd8dfd7b826718df16017dc7e2960ac85dbc98d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 13 Jun 2022 11:17:41 +0300 Subject: [PATCH] refactor Quaternions --- .../kmath/estree/internal/ESTreeBuilder.kt | 7 +- .../kscience/kmath/asm/internal/AsmBuilder.kt | 2 + kmath-complex/build.gradle.kts | 10 +- .../kscience/kmath/complex/Quaternion.kt | 133 ++++++++---------- kmath-geometry/build.gradle.kts | 2 +- .../kmath/geometry/Euclidean2DSpace.kt | 3 - .../kmath/geometry/Euclidean3DSpace.kt | 2 - 7 files changed, 68 insertions(+), 91 deletions(-) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt index 10a6c4a16..40c446da0 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -14,11 +14,12 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression { @Suppress("UNUSED_VARIABLE") override fun invoke(arguments: Map): T { - val e = executable - val c = constants + //val e = executable + //val c = constants val a = js("{}") arguments.forEach { (key, value) -> a[key.identity] = value } - return js("e(c, a)").unsafeCast() + return executable.call(constants, a).unsafeCast() + //return js("e(c, a)").unsafeCast() } } diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index a85079fc8..a76b47ecc 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -49,5 +49,7 @@ internal abstract class AsmBuilder { * ASM Type for [space.kscience.kmath.expressions.Symbol]. */ val SYMBOL_TYPE: Type = getObjectType("space/kscience/kmath/expressions/Symbol") + + const val ARGUMENTS_NAME = "args" } } diff --git a/kmath-complex/build.gradle.kts b/kmath-complex/build.gradle.kts index ea74df646..f0ce631a5 100644 --- a/kmath-complex/build.gradle.kts +++ b/kmath-complex/build.gradle.kts @@ -19,13 +19,15 @@ readme { feature( id = "complex", - description = "Complex Numbers", ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt" - ) + ){ + "Complex numbers operations" + } feature( id = "quaternion", - description = "Quaternions", ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt" - ) + ){ + "Quaternions and their composition" + } } diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt index 3ef3428c6..85c945faf 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -16,6 +16,52 @@ import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableMemoryBuffer import kotlin.math.* +/** + * Represents `double`-based quaternion. + * + * @property w The first component. + * @property x The second component. + * @property y The third component. + * @property z The fourth component. + */ +public data class Quaternion( + val w: Double, val x: Double, val y: Double, val z: Double, +) { + init { + require(!w.isNaN()) { "w-component of quaternion is not-a-number" } + require(!x.isNaN()) { "x-component of quaternion is not-a-number" } + require(!y.isNaN()) { "y-component of quaternion is not-a-number" } + require(!z.isNaN()) { "z-component of quaternion is not-a-number" } + } + + /** + * Returns a string representation of this quaternion. + */ + override fun toString(): String = "($w + $x * i + $y * j + $z * k)" + + public companion object : MemorySpec { + override val objectSize: Int + get() = 32 + + override fun MemoryReader.read(offset: Int): Quaternion = + Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24)) + + override fun MemoryWriter.write(offset: Int, value: Quaternion) { + writeDouble(offset, value.w) + writeDouble(offset + 8, value.x) + writeDouble(offset + 16, value.y) + writeDouble(offset + 24, value.z) + } + } +} + +public fun Quaternion(w: Number, x: Number = 0.0, y: Number = 0.0, z: Number = 0.0): Quaternion = Quaternion( + w.toDouble(), + x.toDouble(), + y.toDouble(), + z.toDouble(), +) + /** * This quaternion's conjugate. */ @@ -45,23 +91,23 @@ public val Quaternion.r: Double @OptIn(UnstableKMathAPI::class) public object QuaternionField : Field, Norm, PowerOperations, ExponentialOperations, NumbersAddOps, ScaleOperations { - override val zero: Quaternion = 0.toQuaternion() - override val one: Quaternion = 1.toQuaternion() + override val zero: Quaternion = Quaternion(0.0) + override val one: Quaternion = Quaternion(1.0) /** * The `i` quaternion unit. */ - public val i: Quaternion = Quaternion(0, 1) + public val i: Quaternion = Quaternion(0.0, 1.0, 0.0, 0.0) /** * The `j` quaternion unit. */ - public val j: Quaternion = Quaternion(0, 0, 1) + public val j: Quaternion = Quaternion(0.0, 0.0, 1.0, 0.0) /** * The `k` quaternion unit. */ - public val k: Quaternion = Quaternion(0, 0, 0, 1) + public val k: Quaternion = Quaternion(0.0, 0.0, 0.0, 1.0) override fun add(left: Quaternion, right: Quaternion): Quaternion = Quaternion(left.w + right.w, left.x + right.x, left.y + right.y, left.z + right.z) @@ -133,7 +179,7 @@ public object QuaternionField : Field, Norm, override fun exp(arg: Quaternion): Quaternion { val un = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z - if (un == 0.0) return exp(arg.w).toQuaternion() + if (un == 0.0) return Quaternion(exp(arg.w)) val n1 = sqrt(un) val ea = exp(arg.w) val n2 = ea * sin(n1) / n1 @@ -158,7 +204,8 @@ public object QuaternionField : Field, Norm, return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z) } - override operator fun Number.plus(other: Quaternion): Quaternion = Quaternion(toDouble() + other.w, other.x, other.y, other.z) + override operator fun Number.plus(other: Quaternion): Quaternion = + Quaternion(toDouble() + other.w, other.x, other.y, other.z) override operator fun Number.minus(other: Quaternion): Quaternion = Quaternion(toDouble() - other.w, -other.x, -other.y, -other.z) @@ -179,7 +226,7 @@ public object QuaternionField : Field, Norm, else -> null } - override fun number(value: Number): Quaternion = value.toQuaternion() + override fun number(value: Number): Quaternion = Quaternion(value) override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0 @@ -189,76 +236,6 @@ public object QuaternionField : Field, Norm, override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0 } -/** - * Represents `double`-based quaternion. - * - * @property w The first component. - * @property x The second component. - * @property y The third component. - * @property z The fourth component. - */ -@OptIn(UnstableKMathAPI::class) -public data class Quaternion( - val w: Double, val x: Double, val y: Double, val z: Double, -) { - public constructor(w: Number, x: Number, y: Number, z: Number) : this( - w.toDouble(), - x.toDouble(), - y.toDouble(), - z.toDouble(), - ) - - public constructor(w: Number, x: Number, y: Number) : this(w.toDouble(), x.toDouble(), y.toDouble(), 0.0) - public constructor(w: Number, x: Number) : this(w.toDouble(), x.toDouble(), 0.0, 0.0) - public constructor(w: Number) : this(w.toDouble(), 0.0, 0.0, 0.0) - public constructor(wx: Complex, yz: Complex) : this(wx.re, wx.im, yz.re, yz.im) - public constructor(wx: Complex) : this(wx.re, wx.im, 0, 0) - - init { - require(!w.isNaN()) { "w-component of quaternion is not-a-number" } - require(!x.isNaN()) { "x-component of quaternion is not-a-number" } - require(!y.isNaN()) { "x-component of quaternion is not-a-number" } - require(!z.isNaN()) { "x-component of quaternion is not-a-number" } - } - - /** - * Returns a string representation of this quaternion. - */ - override fun toString(): String = "($w + $x * i + $y * j + $z * k)" - - public companion object : MemorySpec { - override val objectSize: Int - get() = 32 - - override fun MemoryReader.read(offset: Int): Quaternion = - Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24)) - - override fun MemoryWriter.write(offset: Int, value: Quaternion) { - writeDouble(offset, value.w) - writeDouble(offset + 8, value.x) - writeDouble(offset + 16, value.y) - writeDouble(offset + 24, value.z) - } - } -} - -/** - * Creates a quaternion with real part equal to this real. - * - * @receiver the real part. - * @return a new quaternion. - */ -public fun Number.toQuaternion(): Quaternion = Quaternion(this) - -/** - * Creates a quaternion with `w`-component equal to `re`-component of given complex and `x`-component equal to - * `im`-component of given complex. - * - * @receiver the complex number. - * @return a new quaternion. - */ -public fun Complex.toQuaternion(): Quaternion = Quaternion(this) - /** * Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the * specified [init] function. diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index 7eb814683..bfe2e32a2 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -6,7 +6,7 @@ plugins { kotlin.sourceSets.commonMain { dependencies { - api(project(":kmath-core")) + api(projects.kmath.kmathComplex) } } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt index d00575bcc..a83cb3ac7 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt @@ -6,12 +6,10 @@ package space.kscience.kmath.geometry import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke import kotlin.math.sqrt -@OptIn(UnstableKMathAPI::class) public interface Vector2D : Point, Vector { public val x: Double public val y: Double @@ -29,7 +27,6 @@ public interface Vector2D : Point, Vector { public val Vector2D.r: Double get() = Euclidean2DSpace { norm() } -@Suppress("FunctionName") public fun Vector2D(x: Double, y: Double): Vector2D = Vector2DImpl(x, y) private data class Vector2DImpl( diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt index e12563b46..d3b3fb15e 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt @@ -6,12 +6,10 @@ package space.kscience.kmath.geometry import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke import kotlin.math.sqrt -@OptIn(UnstableKMathAPI::class) public interface Vector3D : Point, Vector { public val x: Double public val y: Double