diff --git a/CHANGELOG.md b/CHANGELOG.md index 9235cfd57..27b67a4d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,14 @@ ## Unreleased ### Added -- Integer divistion algebras +- Integer division algebras +- Float32 geometries ### Changed - Default naming for algebra and buffers now uses IntXX/FloatXX notation instead of Java types. - Remove unnecessary inlines in basic algebras. +- QuaternionField -> QuaternionAlgebra and does not implement `Field` anymore since it is non-commutative +- kmath-geometry is split into `euclidean2d` and `euclidean3d` ### Deprecated 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 d4259c4dc..8f3d15a26 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 @@ -122,16 +122,17 @@ public val Quaternion.reciprocal: Quaternion /** * Produce a normalized version of this quaternion */ -public fun Quaternion.normalized(): Quaternion = with(QuaternionField){ this@normalized / norm(this@normalized) } +public fun Quaternion.normalized(): Quaternion = with(QuaternionAlgebra){ this@normalized / norm(this@normalized) } /** * A field of [Quaternion]. */ @OptIn(UnstableKMathAPI::class) -public object QuaternionField : Field, Norm, PowerOperations, +public object QuaternionAlgebra : Group, Norm, PowerOperations, ExponentialOperations, NumbersAddOps, ScaleOperations { + override val zero: Quaternion = Quaternion(0.0) - override val one: Quaternion = Quaternion(1.0) + public val one: Quaternion = Quaternion(1.0) /** * The `i` quaternion unit. @@ -154,14 +155,16 @@ public object QuaternionField : Field, Norm, Pow override fun scale(a: Quaternion, value: Double): Quaternion = Quaternion(a.w * value, a.x * value, a.y * value, a.z * value) - override fun multiply(left: Quaternion, right: Quaternion): Quaternion = Quaternion( + public fun multiply(left: Quaternion, right: Quaternion): Quaternion = Quaternion( left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z, left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y, left.w * right.y - left.x * right.z + left.y * right.w + left.z * right.x, left.w * right.z + left.x * right.y - left.y * right.x + left.z * right.w, ) - override fun divide(left: Quaternion, right: Quaternion): Quaternion { + public operator fun Quaternion.times(other: Quaternion): Quaternion = multiply(this, other) + + public fun divide(left: Quaternion, right: Quaternion): Quaternion { val s = right.w * right.w + right.x * right.x + right.y * right.y + right.z * right.z return Quaternion( @@ -172,14 +175,17 @@ public object QuaternionField : Field, Norm, Pow ) } + public operator fun Quaternion.div(other: Quaternion): Quaternion = divide(this, other) + + override fun power(arg: Quaternion, pow: Number): Quaternion { - if (pow is Int) return pwr(arg, pow) - if (floor(pow.toDouble()) == pow.toDouble()) return pwr(arg, pow.toInt()) + if (pow is Int) return power(arg, pow) + if (floor(pow.toDouble()) == pow.toDouble()) return power(arg, pow.toInt()) return exp(pow * ln(arg)) } - private fun pwr(x: Quaternion, a: Int): Quaternion = when { - a < 0 -> -(pwr(x, -a)) + private fun power(x: Quaternion, a: Int): Quaternion = when { + a < 0 -> -(power(x, -a)) a == 0 -> one a == 1 -> x a == 2 -> pwr2(x) @@ -243,14 +249,15 @@ public object QuaternionField : Field, Norm, Pow return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z) } - override operator fun Number.plus(other: Quaternion): Quaternion = + public 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 = + public override operator fun Number.minus(other: Quaternion): Quaternion = Quaternion(toDouble() - other.w, -other.x, -other.y, -other.z) - override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z) - override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z) + public override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z) + + public override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z) override operator fun Number.times(arg: Quaternion): Quaternion = Quaternion(toDouble() * arg.w, toDouble() * arg.x, toDouble() * arg.y, toDouble() * arg.z) @@ -275,7 +282,7 @@ public object QuaternionField : Field, Norm, Pow override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0 override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) - override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg) + override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(pwr2(arg) + one) + arg) override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one))) override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0 } diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt index fd0fd46a7..1b371adca 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt @@ -14,20 +14,20 @@ internal class QuaternionTest { @Test fun testNorm() { - assertEquals(2.0, QuaternionField.norm(Quaternion(1.0, 1.0, 1.0, 1.0))) + assertEquals(2.0, QuaternionAlgebra.norm(Quaternion(1.0, 1.0, 1.0, 1.0))) } @Test - fun testInverse() = QuaternionField { + fun testInverse() = QuaternionAlgebra { val q = Quaternion(1.0, 2.0, -3.0, 4.0) assertBufferEquals(one, q * q.reciprocal, 1e-4) } @Test fun testAddition() { - assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(16, 16) + Quaternion(26, 26) }) - assertEquals(Quaternion(42, 16), QuaternionField { Quaternion(16, 16) + 26 }) - assertEquals(Quaternion(42, 16), QuaternionField { 26 + Quaternion(16, 16) }) + assertEquals(Quaternion(42, 42), QuaternionAlgebra { Quaternion(16, 16) + Quaternion(26, 26) }) + assertEquals(Quaternion(42, 16), QuaternionAlgebra { Quaternion(16, 16) + 26 }) + assertEquals(Quaternion(42, 16), QuaternionAlgebra { 26 + Quaternion(16, 16) }) } // @Test @@ -39,9 +39,9 @@ internal class QuaternionTest { @Test fun testMultiplication() { - assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(4.2, 0) * Quaternion(10, 10) }) - assertEquals(Quaternion(42, 21), QuaternionField { Quaternion(4.2, 2.1) * 10 }) - assertEquals(Quaternion(42, 21), QuaternionField { 10 * Quaternion(4.2, 2.1) }) + assertEquals(Quaternion(42, 42), QuaternionAlgebra { Quaternion(4.2, 0) * Quaternion(10, 10) }) + assertEquals(Quaternion(42, 21), QuaternionAlgebra { Quaternion(4.2, 2.1) * 10 }) + assertEquals(Quaternion(42, 21), QuaternionAlgebra { 10 * Quaternion(4.2, 2.1) }) } // @Test @@ -53,11 +53,11 @@ internal class QuaternionTest { @Test fun testPower() { - assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 }) - assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 }) + assertEquals(QuaternionAlgebra.zero, QuaternionAlgebra { zero pow 2 }) + assertEquals(QuaternionAlgebra.zero, QuaternionAlgebra { zero pow 2 }) assertEquals( - QuaternionField { i * 8 }.let { it.x.toInt() to it.w.toInt() }, - QuaternionField { Quaternion(2, 2) pow 2 }.let { it.x.toInt() to it.w.toInt() }) + QuaternionAlgebra { i * 8 }.let { it.x.toInt() to it.w.toInt() }, + QuaternionAlgebra { Quaternion(2, 2) pow 2 }.let { it.x.toInt() to it.w.toInt() }) } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt index 0960ab023..67f37ed62 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt @@ -300,7 +300,7 @@ public interface Ring : Group, RingOps { * commutative operations [add] and [multiply]; binary operation [divide] as multiplication of left operand by * reciprocal of right one. * - * @param T the type of element of this semifield. + * @param T the type of the semifield element. */ public interface FieldOps : RingOps { /** @@ -336,10 +336,12 @@ public interface FieldOps : RingOps { /** * Represents field i.e., algebraic structure with three operations: associative, commutative addition and - * multiplication, and division. **This interface differs from the eponymous mathematical definition: fields in KMath + * multiplication, and division. + * + * **This interface differs from the eponymous mathematical definition: fields in KMath * also support associative multiplication by scalar.** * - * @param T the type of element of this field. + * @param T the type of the field element. */ public interface Field : Ring, FieldOps, ScaleOperations, NumericAlgebra { override fun number(value: Number): T = scale(one, value.toDouble()) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt index 9bcfb00a2..06ad68298 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt @@ -150,7 +150,7 @@ public interface ScaleOperations : Algebra { * TODO to be removed and replaced by extensions after multiple receivers are there */ @UnstableKMathAPI -public interface NumbersAddOps : RingOps, NumericAlgebra { +public interface NumbersAddOps : GroupOps, NumericAlgebra { /** * Addition of element and scalar. * @@ -177,7 +177,7 @@ public interface NumbersAddOps : RingOps, NumericAlgebra { public operator fun T.minus(other: Number): T = this - number(other) /** - * Subtraction of number from element. + * Subtraction of number from the element. * * @receiver the minuend. * @param other the subtrahend. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt index c24394add..48cac2870 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt @@ -82,9 +82,9 @@ public expect fun Number.isInteger(): Boolean /** * A context extension to include power operations based on exponentiation. * - * @param T the type of element of this structure. + * @param T the type of this structure element */ -public interface PowerOperations : FieldOps { +public interface PowerOperations: Algebra { /** * Raises [arg] to a power if possible (negative number could not be raised to a fractional power). diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt index 108b840dd..d13528636 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt @@ -16,7 +16,6 @@ import kotlin.math.pow public typealias DoubleVector = Point -@Suppress("FunctionName") public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer() /** diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt index a7f6ae35d..92d31a7cb 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt @@ -7,6 +7,8 @@ package space.kscience.kmath.geometry import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.kmath.geometry.euclidean2d.DoubleVector2D +import space.kscience.kmath.geometry.euclidean3d.DoubleVector3D /** * A line formed by [start] vector of start and a [direction] vector. Direction vector is not necessarily normalized, diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector2D.kt new file mode 100644 index 000000000..9eced7ba9 --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector2D.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.geometry + +import space.kscience.kmath.linear.Point + +public interface Vector2D : Point, Vector { + public val x: T + public val y: T + override val size: Int get() = 2 + + override operator fun get(index: Int): T = when (index) { + 0 -> x + 1 -> y + else -> error("Accessing outside of point bounds") + } + + override operator fun iterator(): Iterator = iterator { + yield(x) + yield(y) + } +} + + +public operator fun Vector2D.component1(): T = x +public operator fun Vector2D.component2(): T = y \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector3D.kt new file mode 100644 index 000000000..7e7c6c4ed --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector3D.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.geometry + +import space.kscience.kmath.linear.Point +import space.kscience.kmath.structures.Buffer + +public interface Vector3D : Point, Vector { + public val x: T + public val y: T + public val z: T + override val size: Int get() = 3 + + override operator fun get(index: Int): T = when (index) { + 0 -> x + 1 -> y + 2 -> z + else -> error("Accessing outside of point bounds") + } + + override operator fun iterator(): Iterator = listOf(x, y, z).iterator() +} + +public operator fun Vector3D.component1(): T = x +public operator fun Vector3D.component2(): T = y +public operator fun Vector3D.component3(): T = z + +public fun Buffer.asVector3D(): Vector3D = object : Vector3D { + init { + require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" } + } + + override val x: T get() = this@asVector3D[0] + override val y: T get() = this@asVector3D[1] + override val z: T get() = this@asVector3D[2] + + override fun toString(): String = this@asVector3D.toString() +} \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt similarity index 56% rename from kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt rename to kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt index d37ed45c0..7841be8ff 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt @@ -1,20 +1,19 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2023 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.geometry +package space.kscience.kmath.geometry.euclidean2d import kotlinx.serialization.Serializable -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import kotlin.math.* +import kotlin.math.PI /** * A circle in 2D space */ @Serializable public data class Circle2D( - @Serializable(Euclidean2DSpace.VectorSerializer::class) public val center: DoubleVector2D, + @Serializable(Float64Space2D.VectorSerializer::class) public val center: DoubleVector2D, public val radius: Double ) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float32Space2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float32Space2D.kt new file mode 100644 index 000000000..89c3dc204 --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float32Space2D.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.geometry.euclidean2d + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import space.kscience.kmath.geometry.GeometrySpace +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.operations.Float32Field +import space.kscience.kmath.operations.ScaleOperations +import kotlin.math.pow +import kotlin.math.sqrt + +@Serializable(Float32Space2D.VectorSerializer::class) +public interface Float32Vector2D: Vector2D + + +public object Float32Space2D : + GeometrySpace, + ScaleOperations { + + @Serializable + @SerialName("Float32Vector2D") + private data class Vector2DImpl( + override val x: Float, + override val y: Float, + ) : Float32Vector2D + + public object VectorSerializer : KSerializer { + private val proxySerializer = Vector2DImpl.serializer() + override val descriptor: SerialDescriptor get() = proxySerializer.descriptor + + override fun deserialize(decoder: Decoder): Float32Vector2D = decoder.decodeSerializableValue(proxySerializer) + + override fun serialize(encoder: Encoder, value: Float32Vector2D) { + val vector = value as? Vector2DImpl ?: Vector2DImpl(value.x, value.y) + encoder.encodeSerializableValue(proxySerializer, vector) + } + } + + public fun vector(x: Float, y: Float): Float32Vector2D = + Vector2DImpl(x, y) + + public fun vector(x: Number, y: Number): Float32Vector2D = + vector(x.toFloat(), y.toFloat()) + + override val zero: Float32Vector2D by lazy { vector(0f, 0f) } + + override fun norm(arg: Float32Vector2D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2)).toDouble() + + public fun Float32Vector2D.norm(): Double = norm(this) + + override fun Float32Vector2D.unaryMinus(): Float32Vector2D = vector(-x, -y) + + override fun Float32Vector2D.distanceTo(other: Float32Vector2D): Double = (this - other).norm() + + override fun add(left: Float32Vector2D, right: Float32Vector2D): Float32Vector2D = + vector(left.x + right.x, left.y + right.y) + + override fun scale(a: Float32Vector2D, value: Double): Float32Vector2D = + vector(a.x * value, a.y * value) + + override fun Float32Vector2D.dot(other: Float32Vector2D): Double = + (x * other.x + y * other.y).toDouble() + + public val xAxis: Float32Vector2D = vector(1.0, 0.0) + public val yAxis: Float32Vector2D = vector(0.0, 1.0) +} + +public fun Float32Vector2D(x: Number, y: Number): Float32Vector2D = Float32Space2D.vector(x, y) + +public val Float32Field.euclidean2D: Float32Space2D get() = Float32Space2D diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float64Space2D.kt similarity index 75% rename from kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt rename to kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float64Space2D.kt index 3df8dba7b..030a46185 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float64Space2D.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2023 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.geometry +package space.kscience.kmath.geometry.euclidean2d import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName @@ -11,43 +11,26 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import space.kscience.kmath.linear.Point +import space.kscience.kmath.geometry.GeometrySpace +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.ScaleOperations import kotlin.math.pow import kotlin.math.sqrt -public interface Vector2D : Point, Vector { - public val x: T - public val y: T - override val size: Int get() = 2 - override operator fun get(index: Int): T = when (index) { - 0 -> x - 1 -> y - else -> error("Accessing outside of point bounds") - } - - override operator fun iterator(): Iterator = iterator { - yield(x) - yield(y) - } -} - - -public operator fun Vector2D.component1(): T = x -public operator fun Vector2D.component2(): T = y public typealias DoubleVector2D = Vector2D public typealias Float64Vector2D = Vector2D -public val Vector2D.r: Double get() = Euclidean2DSpace.norm(this) +public val Vector2D.r: Double get() = Float64Space2D.norm(this) /** * 2D Euclidean space */ -public object Euclidean2DSpace : GeometrySpace, +public object Float64Space2D : GeometrySpace, ScaleOperations, Norm { @@ -88,3 +71,5 @@ public object Euclidean2DSpace : GeometrySpace, public val xAxis: DoubleVector2D = vector(1.0, 0.0) public val yAxis: DoubleVector2D = vector(0.0, 1.0) } + +public val Float64Field.euclidean2D: Float64Space2D get() = Float64Space2D \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Polygon.kt similarity index 74% rename from kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt rename to kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Polygon.kt index 20f4a031e..85b377a56 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Polygon.kt @@ -3,7 +3,9 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.geometry +package space.kscience.kmath.geometry.euclidean2d + +import space.kscience.kmath.geometry.Vector2D /** diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float32Space3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float32Space3D.kt new file mode 100644 index 000000000..1413a885b --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float32Space3D.kt @@ -0,0 +1,108 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.geometry.euclidean3d + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import space.kscience.kmath.geometry.GeometrySpace +import space.kscience.kmath.geometry.Vector3D +import space.kscience.kmath.operations.Float32Field +import space.kscience.kmath.operations.ScaleOperations +import kotlin.math.pow +import kotlin.math.sqrt + +@Serializable(Float32Space3D.VectorSerializer::class) +public interface Float32Vector3D: Vector3D + + +public object Float32Space3D : + GeometrySpace, + ScaleOperations{ + + @Serializable + @SerialName("Float32Vector3D") + private data class Vector3DImpl( + override val x: Float, + override val y: Float, + override val z: Float, + ) : Float32Vector3D + + public object VectorSerializer : KSerializer { + private val proxySerializer = Vector3DImpl.serializer() + override val descriptor: SerialDescriptor get() = proxySerializer.descriptor + + override fun deserialize(decoder: Decoder): Float32Vector3D = decoder.decodeSerializableValue(proxySerializer) + + override fun serialize(encoder: Encoder, value: Float32Vector3D) { + val vector = value as? Vector3DImpl ?: Vector3DImpl(value.x, value.y, value.z) + encoder.encodeSerializableValue(proxySerializer, vector) + } + } + + public fun vector(x: Float, y: Float, z: Float): Float32Vector3D = + Vector3DImpl(x, y, z) + + public fun vector(x: Number, y: Number, z: Number): Float32Vector3D = + vector(x.toFloat(), y.toFloat(), z.toFloat()) + + override val zero: Float32Vector3D by lazy { vector(0.0, 0.0, 0.0) } + + override fun norm(arg: Float32Vector3D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2) + arg.z.pow(2)).toDouble() + + public fun Float32Vector3D.norm(): Double = norm(this) + + override fun Float32Vector3D.unaryMinus(): Float32Vector3D = vector(-x, -y, -z) + + override fun Float32Vector3D.distanceTo(other: Float32Vector3D): Double = (this - other).norm() + + override fun add(left: Float32Vector3D, right: Float32Vector3D): Float32Vector3D = + vector(left.x + right.x, left.y + right.y, left.z + right.z) + + override fun scale(a: Float32Vector3D, value: Double): Float32Vector3D = + vector(a.x * value, a.y * value, a.z * value) + + override fun Float32Vector3D.dot(other: Float32Vector3D): Double = + (x * other.x + y * other.y + z * other.z).toDouble() + + /** + * Compute vector product of [first] and [second]. The basis is assumed to be right-handed. + */ + public fun vectorProduct( + first: Float32Vector3D, + second: Float32Vector3D, + ): Float32Vector3D { + var x = 0.0 + var y = 0.0 + var z = 0.0 + + for (j in (0..2)) { + for (k in (0..2)) { + x += leviCivita(0, j, k) * first[j] * second[k] + y += leviCivita(1, j, k) * first[j] * second[k] + z += leviCivita(2, j, k) * first[j] * second[k] + } + } + + return vector(x, y, z) + } + + /** + * Vector product in a right-handed basis + */ + public infix fun Float32Vector3D.cross(other: Float32Vector3D): Float32Vector3D = vectorProduct(this, other) + + public val xAxis: Float32Vector3D = vector(1.0, 0.0, 0.0) + public val yAxis: Float32Vector3D = vector(0.0, 1.0, 0.0) + public val zAxis: Float32Vector3D = vector(0.0, 0.0, 1.0) +} + +public fun Float32Vector3D(x: Number, y: Number, z: Number): Float32Vector3D = Float32Space3D.vector(x, y, z) + +public val Float32Field.euclidean3D: Float32Space3D get() = Float32Space3D \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt similarity index 66% rename from kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt rename to kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt index 3059cefe6..a8c7e1d17 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt @@ -1,9 +1,9 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2023 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.geometry +package space.kscience.kmath.geometry.euclidean3d import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName @@ -11,51 +11,33 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import space.kscience.kmath.linear.Point +import space.kscience.kmath.geometry.GeometrySpace +import space.kscience.kmath.geometry.Vector3D +import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.structures.Buffer import kotlin.math.pow import kotlin.math.sqrt -public interface Vector3D : Point, Vector { - public val x: T - public val y: T - public val z: T - override val size: Int get() = 3 +internal fun leviCivita(i: Int, j: Int, k: Int): Int = when { + // even permutation + i == 0 && j == 1 && k == 2 -> 1 + i == 1 && j == 2 && k == 0 -> 1 + i == 2 && j == 0 && k == 1 -> 1 + // odd permutations + i == 2 && j == 1 && k == 0 -> -1 + i == 0 && j == 2 && k == 1 -> -1 + i == 1 && j == 0 && k == 2 -> -1 - override operator fun get(index: Int): T = when (index) { - 0 -> x - 1 -> y - 2 -> z - else -> error("Accessing outside of point bounds") - } - - override operator fun iterator(): Iterator = listOf(x, y, z).iterator() -} - -public operator fun Vector3D.component1(): T = x -public operator fun Vector3D.component2(): T = y -public operator fun Vector3D.component3(): T = z - -public fun Buffer.asVector3D(): Vector3D = object : Vector3D { - init { - require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" } - } - - override val x: T get() = this@asVector3D[0] - override val y: T get() = this@asVector3D[1] - override val z: T get() = this@asVector3D[2] - - override fun toString(): String = this@asVector3D.toString() + else -> 0 } public typealias DoubleVector3D = Vector3D public typealias Float64Vector3D = Vector3D -public val DoubleVector3D.r: Double get() = Euclidean3DSpace.norm(this) +public val DoubleVector3D.r: Double get() = Float64Space3D.norm(this) -public object Euclidean3DSpace : GeometrySpace, ScaleOperations, +public object Float64Space3D : GeometrySpace, ScaleOperations, Norm { @Serializable @@ -103,21 +85,8 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations< override fun DoubleVector3D.dot(other: DoubleVector3D): Double = x * other.x + y * other.y + z * other.z - private fun leviCivita(i: Int, j: Int, k: Int): Int = when { - // even permutation - i == 0 && j == 1 && k == 2 -> 1 - i == 1 && j == 2 && k == 0 -> 1 - i == 2 && j == 0 && k == 1 -> 1 - // odd permutations - i == 2 && j == 1 && k == 0 -> -1 - i == 0 && j == 2 && k == 1 -> -1 - i == 1 && j == 0 && k == 2 -> -1 - - else -> 0 - } - /** - * Compute vector product of [first] and [second]. The basis assumed to be right-handed. + * Compute vector product of [first] and [second]. The basis is assumed to be right-handed. */ public fun vectorProduct( first: DoubleVector3D, @@ -139,7 +108,7 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations< } /** - * Vector product with right basis + * Vector product with the right basis */ public infix fun DoubleVector3D.cross(other: DoubleVector3D): Vector3D = vectorProduct(this, other) @@ -147,3 +116,5 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations< public val yAxis: DoubleVector3D = vector(0.0, 1.0, 0.0) public val zAxis: DoubleVector3D = vector(0.0, 0.0, 1.0) } + +public val Float64Field.euclidean3D: Float64Space3D get() = Float64Space3D diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt similarity index 89% rename from kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt rename to kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt index 688386e3b..deb8b0a93 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt @@ -1,15 +1,16 @@ /* - * Copyright 2018-2022 KMath contributors. + * Copyright 2018-2023 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.geometry +package space.kscience.kmath.geometry.euclidean3d import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.complex.Quaternion -import space.kscience.kmath.complex.QuaternionField +import space.kscience.kmath.complex.QuaternionAlgebra import space.kscience.kmath.complex.normalized import space.kscience.kmath.complex.reciprocal +import space.kscience.kmath.geometry.* import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.linearSpace @@ -31,7 +32,7 @@ public val Quaternion.theta: Radians get() = (kotlin.math.acos(normalized().w) * public fun Quaternion.Companion.fromRotation(theta: Angle, vector: DoubleVector3D): Quaternion { val s = sin(theta / 2) val c = cos(theta / 2) - val norm = with(Euclidean3DSpace) { vector.norm() } + val norm = with(Float64Space3D) { vector.norm() } return Quaternion(c, vector.x * s / norm, vector.y * s / norm, vector.z * s / norm) } @@ -50,9 +51,9 @@ public val Quaternion.vector: DoubleVector3D } /** - * Rotate a vector in a [Euclidean3DSpace] + * Rotate a vector in a [Float64Space3D] */ -public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, q: Quaternion): DoubleVector3D = with(QuaternionField) { +public fun Float64Space3D.rotate(vector: DoubleVector3D, q: Quaternion): DoubleVector3D = with(QuaternionAlgebra) { val p = vector.toQuaternion() (q * p * q.reciprocal).vector } @@ -61,10 +62,10 @@ public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, q: Quaternion): Doubl * Use a composition of quaternions to create a rotation */ @UnstableKMathAPI -public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, composition: QuaternionField.() -> Quaternion): DoubleVector3D = - rotate(vector, QuaternionField.composition()) +public fun Float64Space3D.rotate(vector: DoubleVector3D, composition: QuaternionAlgebra.() -> Quaternion): DoubleVector3D = + rotate(vector, QuaternionAlgebra.composition()) -public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, matrix: Matrix): DoubleVector3D { +public fun Float64Space3D.rotate(vector: DoubleVector3D, matrix: Matrix): DoubleVector3D { require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" } return with(Float64Field.linearSpace) { matrix.dot(vector).asVector3D() } } @@ -76,7 +77,7 @@ public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, matrix: Matrix = Float64Field.linearSpace, ): Matrix { - val s = QuaternionField.norm(this).pow(-2) + val s = QuaternionAlgebra.norm(this).pow(-2) return linearSpace.matrix(3, 3)( 1.0 - 2 * s * (y * y + z * z), 2 * s * (x * y - z * w), 2 * s * (x * z + y * w), 2 * s * (x * y + z * w), 1.0 - 2 * s * (x * x + z * z), 2 * s * (y * z - x * w), diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt index ea46ab90f..2ed02182d 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt @@ -6,6 +6,10 @@ package space.kscience.kmath.geometry import space.kscience.kmath.geometry.GeometrySpace.Companion.DEFAULT_PRECISION +import space.kscience.kmath.geometry.euclidean2d.Float64Space2D +import space.kscience.kmath.geometry.euclidean2d.Float64Vector2D +import space.kscience.kmath.geometry.euclidean3d.Float64Space3D +import space.kscience.kmath.geometry.euclidean3d.Float64Vector3D /** * Float equality within given [precision] @@ -36,7 +40,7 @@ public fun V.equalsVector( public fun Float64Vector2D.equalsVector( other: Float64Vector2D, precision: Double = DEFAULT_PRECISION, -): Boolean = equalsVector(Euclidean2DSpace, other, precision) +): Boolean = equalsVector(Float64Space2D, other, precision) /** * Vector equality using Euclidian L2 norm and given [precision] @@ -44,7 +48,7 @@ public fun Float64Vector2D.equalsVector( public fun Float64Vector3D.equalsVector( other: Float64Vector3D, precision: Double = DEFAULT_PRECISION, -): Boolean = equalsVector(Euclidean3DSpace, other, precision) +): Boolean = equalsVector(Float64Space3D, other, precision) /** * Line equality using [GeometrySpace.norm] provided by the [space] and given [precision] diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/quaternionOperations.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/quaternionOperations.kt new file mode 100644 index 000000000..49ceda04c --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/quaternionOperations.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2018-2023 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.geometry + +import space.kscience.kmath.complex.Quaternion +import space.kscience.kmath.complex.QuaternionAlgebra +import space.kscience.kmath.complex.conjugate +import space.kscience.kmath.complex.normalized +import space.kscience.kmath.geometry.euclidean3d.Float32Space3D +import space.kscience.kmath.geometry.euclidean3d.Float32Vector3D +import space.kscience.kmath.geometry.euclidean3d.theta +import kotlin.math.asin +import kotlin.math.atan2 +import kotlin.math.pow + +public operator fun Quaternion.times(other: Quaternion): Quaternion = QuaternionAlgebra.multiply(this, other) + +public operator fun Quaternion.div(other: Quaternion): Quaternion = QuaternionAlgebra.divide(this, other) + +public fun Quaternion.power(number: Number): Quaternion = QuaternionAlgebra.power(this, number) + +/** + * Linear interpolation between [from] and [to] in spherical space + */ +public fun QuaternionAlgebra.slerp(from: Quaternion, to: Quaternion, fraction: Double): Quaternion = + (to / from).pow(fraction) * from + +public fun QuaternionAlgebra.angleBetween(q1: Quaternion, q2: Quaternion): Angle = (q1.conjugate * q2).theta + +public val Quaternion.inclination: Radians get() = asin(2 * (w * y - x * z)).radians + +public val Quaternion.azimuth: Angle get() = atan2(2 * (w * z + x * y), 1 - 2 * (y.pow(2) + z.pow(2))).radians.normalized() + +public infix fun Quaternion.dot(other: Quaternion): Double = w * other.w + x * other.x + y * other.y + z * other.z + + +private fun Quaternion.normalizedToEuler(): Float32Vector3D { + val roll = atan2(2 * y * w + 2 * x * z, 1 - 2 * y * y - 2 * z * z); + val pitch = atan2(2 * x * w - 2 * y * z, 1 - 2 * x * x - 2 * z * z); + val yaw = asin(2 * x * y + 2 * z * w); + + return Float32Vector3D(roll, pitch, yaw) +} + +/** + * Quaternion to XYZ Cardan angles + */ +public fun Quaternion.toEuler(): Float32Vector3D = if (QuaternionAlgebra.norm(this) == 0.0) { + Float32Space3D.zero +} else { + normalized().normalizedToEuler() +} \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt index 22cbee6f0..7c5ee3485 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.geometry +import space.kscience.kmath.geometry.euclidean2d.Float64Space2D import kotlin.math.sqrt import kotlin.test.Test import kotlin.test.assertEquals @@ -12,12 +13,12 @@ import kotlin.test.assertEquals internal class Euclidean2DSpaceTest { @Test fun zero() { - assertVectorEquals(Euclidean2DSpace.vector(0.0, 0.0), Euclidean2DSpace.zero) + assertVectorEquals(Float64Space2D.vector(0.0, 0.0), Float64Space2D.zero) } @Test fun norm() { - with(Euclidean2DSpace) { + with(Float64Space2D) { assertEquals(0.0, norm(zero)) assertEquals(1.0, norm(vector(1.0, 0.0))) assertEquals(sqrt(2.0), norm(vector(1.0, 1.0))) @@ -27,7 +28,7 @@ internal class Euclidean2DSpaceTest { @Test fun dotProduct() { - with(Euclidean2DSpace) { + with(Float64Space2D) { assertEquals(0.0, zero dot zero) assertEquals(0.0, zero dot vector(1.0, 0.0)) assertEquals(0.0, vector(-2.0, 0.001) dot zero) @@ -44,7 +45,7 @@ internal class Euclidean2DSpaceTest { @Test fun add() { - with(Euclidean2DSpace) { + with(Float64Space2D) { assertVectorEquals( vector(-2.0, 0.001), vector(-2.0, 0.001) + zero @@ -58,7 +59,7 @@ internal class Euclidean2DSpaceTest { @Test fun multiply() { - with(Euclidean2DSpace) { + with(Float64Space2D) { assertVectorEquals(vector(-4.0, 0.0), vector(-2.0, 0.0) * 2) assertVectorEquals(vector(4.0, 0.0), vector(-2.0, 0.0) * -2) assertVectorEquals(vector(300.0, 0.0003), vector(100.0, 0.0001) * 3) diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt index 20e112ad1..f881deb1b 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt @@ -5,18 +5,19 @@ package space.kscience.kmath.geometry +import space.kscience.kmath.geometry.euclidean3d.Float64Space3D import kotlin.test.Test import kotlin.test.assertEquals internal class Euclidean3DSpaceTest { @Test fun zero() { - assertVectorEquals(Euclidean3DSpace.vector(0.0, 0.0, 0.0), Euclidean3DSpace.zero) + assertVectorEquals(Float64Space3D.vector(0.0, 0.0, 0.0), Float64Space3D.zero) } @Test fun distance() { - with(Euclidean3DSpace) { + with(Float64Space3D) { assertEquals(0.0, zero.distanceTo(zero)) assertEquals(1.0, zero.distanceTo(vector(1.0, 0.0, 0.0))) assertEquals(kotlin.math.sqrt(5.000001), vector(1.0, -2.0, 0.001).distanceTo(zero)) @@ -31,7 +32,7 @@ internal class Euclidean3DSpaceTest { @Test fun norm() { - with(Euclidean3DSpace) { + with(Float64Space3D) { assertEquals(0.0, zero.norm()) assertEquals(1.0, vector(1.0, 0.0, 0.0).norm()) assertEquals(kotlin.math.sqrt(3.0), vector(1.0, 1.0, 1.0).norm()) @@ -41,7 +42,7 @@ internal class Euclidean3DSpaceTest { @Test fun dotProduct() { - with(Euclidean3DSpace) { + with(Float64Space3D) { assertEquals(0.0, zero dot zero) assertEquals(0.0, zero dot vector(1.0, 0.0, 0.0)) assertEquals(0.0, vector(1.0, -2.0, 0.001) dot zero) @@ -57,7 +58,7 @@ internal class Euclidean3DSpaceTest { } @Test - fun add() = with(Euclidean3DSpace) { + fun add() = with(Float64Space3D) { assertVectorEquals( vector(1.0, -2.0, 0.001), vector(1.0, -2.0, 0.001) + zero @@ -69,19 +70,19 @@ internal class Euclidean3DSpaceTest { } @Test - fun multiply() = with(Euclidean3DSpace) { + fun multiply() = with(Float64Space3D) { assertVectorEquals(vector(2.0, -4.0, 0.0), vector(1.0, -2.0, 0.0) * 2) } @Test - fun vectorProduct() = with(Euclidean3DSpace) { + fun vectorProduct() = with(Float64Space3D) { assertVectorEquals(zAxis, vectorProduct(xAxis, yAxis)) assertVectorEquals(zAxis, xAxis cross yAxis) assertVectorEquals(-zAxis, vectorProduct(yAxis, xAxis)) } @Test - fun doubleVectorProduct() = with(Euclidean3DSpace) { + fun doubleVectorProduct() = with(Float64Space3D) { val a = vector(1, 2, -3) val b = vector(-1, 0, 1) val c = vector(4, 5, 6) diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt index cc74b06e3..9b3f40c4c 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt @@ -5,13 +5,15 @@ package space.kscience.kmath.geometry +import space.kscience.kmath.geometry.euclidean2d.Float64Space2D +import space.kscience.kmath.geometry.euclidean3d.Float64Space3D import kotlin.test.Test import kotlin.test.assertTrue internal class ProjectionAlongTest { @Test fun projectionIntoYEqualsX() { - with(Euclidean2DSpace) { + with(Float64Space2D) { val normal = vector(-2.0, 2.0) val base = vector(2.3, 2.3) @@ -26,7 +28,7 @@ internal class ProjectionAlongTest { @Test fun projectionOntoLine() { - with(Euclidean2DSpace) { + with(Float64Space2D) { val a = 5.0 val b = -3.0 val c = -15.0 @@ -42,11 +44,11 @@ internal class ProjectionAlongTest { } @Test - fun projectOntoPlane() = with(Euclidean3DSpace){ + fun projectOntoPlane() = with(Float64Space3D){ val normal = vector(1.0, 3.5, 0.07) val base = vector(2.0, -0.0037, 11.1111) - with(Euclidean3DSpace) { + with(Float64Space3D) { val testDomain = (-10.0..10.0).generateList(0.43) for (x in testDomain) { for (y in testDomain) { diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt index 7c6c105cf..d3a9d1171 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt @@ -5,13 +5,15 @@ package space.kscience.kmath.geometry +import space.kscience.kmath.geometry.euclidean2d.Float64Space2D +import space.kscience.kmath.geometry.euclidean3d.Float64Space3D import kotlin.test.Test import kotlin.test.assertTrue internal class ProjectionOntoLineTest { @Test fun projectionIntoOx() { - with(Euclidean2DSpace) { + with(Float64Space2D) { val ox = Line(zero, vector(1.0, 0.0)) grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> @@ -22,7 +24,7 @@ internal class ProjectionOntoLineTest { @Test fun projectionIntoOy() { - with(Euclidean2DSpace) { + with(Float64Space2D) { val line = Line(zero, vector(0.0, 1.0)) grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> @@ -33,7 +35,7 @@ internal class ProjectionOntoLineTest { @Test fun projectionIntoYEqualsX() { - with(Euclidean2DSpace) { + with(Float64Space2D) { val line = Line(zero, vector(1.0, 1.0)) assertVectorEquals(zero, projectToLine(zero, line)) @@ -47,7 +49,7 @@ internal class ProjectionOntoLineTest { @Test fun projectionOntoLine2d() { - with(Euclidean2DSpace) { + with(Float64Space2D) { val a = 5.0 val b = -3.0 val c = -15.0 @@ -62,7 +64,7 @@ internal class ProjectionOntoLineTest { } @Test - fun projectionOntoLine3d() = with(Euclidean3DSpace) { + fun projectionOntoLine3d() = with(Float64Space3D) { val line = Line( base = vector(1.0, 3.5, 0.07), direction = vector(2.0, -0.0037, 11.1111) diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt index 33a9bcc01..1d354bf72 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.geometry import space.kscience.kmath.complex.Quaternion import space.kscience.kmath.complex.normalized +import space.kscience.kmath.geometry.euclidean3d.* import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.testutils.assertBufferEquals import kotlin.test.Test @@ -14,7 +15,7 @@ import kotlin.test.Test class RotationTest { @Test - fun differentRotations() = with(Euclidean3DSpace) { + fun differentRotations() = with(Float64Space3D) { val vector = vector(1.0, 1.0, 1.0) val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized() val rotatedByQ = rotate(vector, q) @@ -36,7 +37,7 @@ class RotationTest { @Test fun fromRotation() { - val q = Quaternion.fromRotation(0.3.radians, Euclidean3DSpace.vector(1.0, 1.0, 1.0)) + val q = Quaternion.fromRotation(0.3.radians, Float64Space3D.vector(1.0, 1.0, 1.0)) assertBufferEquals(Float64Buffer(0.9887711, 0.0862781, 0.0862781, 0.0862781), q) } diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt index 0db06f4c8..af27b5e00 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt @@ -6,12 +6,13 @@ package space.kscience.kmath.geometry +import space.kscience.kmath.geometry.euclidean2d.Float64Space2D import space.kscience.kmath.operations.toList import kotlin.test.Test import kotlin.test.assertEquals internal class Vector2DTest { - private val vector = Euclidean2DSpace.vector(1.0, -7.999) + private val vector = Float64Space2D.vector(1.0, -7.999) @Test fun size() { diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt index 1c8607838..b10e650a6 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt @@ -5,12 +5,13 @@ package space.kscience.kmath.geometry +import space.kscience.kmath.geometry.euclidean3d.Float64Space3D import space.kscience.kmath.operations.toList import kotlin.test.Test import kotlin.test.assertEquals internal class Vector3DTest { - private val vector = Euclidean3DSpace.vector(1.0, -7.999, 0.001) + private val vector = Float64Space3D.vector(1.0, -7.999, 0.001) @Test fun size() { diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt index c62af3cd3..521ce9e75 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt @@ -5,6 +5,8 @@ package space.kscience.kmath.geometry +import space.kscience.kmath.geometry.euclidean2d.DoubleVector2D +import space.kscience.kmath.geometry.euclidean3d.DoubleVector3D import kotlin.math.abs import kotlin.test.assertEquals diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt index df8a01208..027318f99 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -16,6 +16,7 @@ import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.FieldOps import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.PowerOperations @@ -32,7 +33,8 @@ internal fun ShapeND.toLongArray(): LongArray = LongArray(size) { get(it).toLong public class DoubleTensorFlowAlgebra internal constructor( graph: Graph, -) : TensorFlowAlgebra(graph), PowerOperations> { +) : TensorFlowAlgebra(graph), FieldOps>, PowerOperations> { override val elementAlgebra: Float64Field get() = Float64Field