Skip to content

Commit 33f2818

Browse files
authored
Merge pull request #195 from Kotlin/V0.3.0
Refactor complex number implementation and handling
2 parents 6f513a7 + 917f82f commit 33f2818

File tree

13 files changed

+372
-145
lines changed

13 files changed

+372
-145
lines changed

multik-core/build.gradle.kts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
@file:OptIn(ExperimentalWasmDsl::class)
1+
@file:OptIn(ExperimentalWasmDsl::class, ExperimentalKotlinGradlePluginApi::class)
22

3+
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
34
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
45
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
56

@@ -22,6 +23,11 @@ val nodeDownloadUrl: String by project
2223

2324
kotlin {
2425
explicitApi()
26+
27+
compilerOptions {
28+
freeCompilerArgs.add("-Xexpect-actual-classes")
29+
}
30+
2531
jvm {
2632
compilations.all {
2733
kotlinOptions.jvmTarget = "1.8"

multik-core/src/commonMain/kotlin/org/jetbrains/kotlinx/multik/ndarray/complex/ComplexDouble.kt

Lines changed: 29 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,31 @@
44

55
package org.jetbrains.kotlinx.multik.ndarray.complex
66

7-
import kotlin.jvm.JvmInline
87
import kotlin.math.atan2
98
import kotlin.math.sqrt
109

10+
/**
11+
* Creates a [ComplexDouble] with the given real and imaginary values in floating-point format.
12+
*
13+
* @param re the real value of the complex number in double format.
14+
* @param im the imaginary value of the complex number in double format.
15+
*/
16+
public expect fun ComplexDouble(re: Double, im: Double): ComplexDouble
17+
18+
/**
19+
* Creates a [ComplexDouble] with the given real and imaginary values in number format.
20+
*
21+
* @param re the real value of the complex number in number format.
22+
* @param im the imaginary value of the complex number in number format.
23+
*/
24+
public expect fun ComplexDouble(re: Number, im: Number): ComplexDouble
25+
26+
/**
27+
* Creates a [ComplexDouble] with a zero imaginary value.
28+
* @param re the real value of the complex number in number format.
29+
*/
30+
public fun ComplexDouble(re: Number): ComplexDouble = ComplexDouble(re.toDouble(), 0.0)
31+
1132
/**
1233
* Represents a complex number with double precision.
1334
* The class is implemented as a double-precision 128-bit complex number.
@@ -40,7 +61,7 @@ import kotlin.math.sqrt
4061
* @property im the imaginary part of the complex number.
4162
* @throws ArithmeticException if division by zero or infinity occurs during division.
4263
*/
43-
public sealed interface ComplexDouble : Complex {
64+
public interface ComplexDouble : Complex {
4465

4566
/**
4667
* The real part of the complex number.
@@ -53,64 +74,23 @@ public sealed interface ComplexDouble : Complex {
5374
public val im: Double
5475

5576
public companion object {
56-
/**
57-
* Determines whether the given double value can be accurately represented as a float value or not.
58-
*
59-
* @param d is the double value to be checked.
60-
* @return this method returns a Boolean value,
61-
* true if the double value can be accurately represented as a float value, false otherwise.
62-
*/
63-
private fun fitsInFloat(d: Double): Boolean = d.toFloat().toDouble() == d
64-
65-
/**
66-
* Creates a [ComplexDouble] with the given real and imaginary values in floating-point format.
67-
*
68-
* @param re the real value of the complex number in double format.
69-
* @param im the imaginary value of the complex number in double format.
70-
*/
71-
public operator fun invoke(re: Double, im: Double): ComplexDouble {
72-
return if (fitsInFloat(re) && fitsInFloat(im))
73-
ComplexDouble32(re, im)
74-
else
75-
ComplexDouble64(re, im)
76-
}
77-
78-
/**
79-
* Creates a [ComplexDouble] with the given real and imaginary values in number format.
80-
*
81-
* @param re the real value of the complex number in number format.
82-
* @param im the imaginary value of the complex number in number format.
83-
*/
84-
public operator fun invoke(re: Number, im: Number): ComplexDouble = invoke(re.toDouble(), im.toDouble())
85-
86-
/**
87-
* Creates a [ComplexDouble] with a zero imaginary value.
88-
* @param re the real value of the complex number in number format.
89-
*/
90-
public operator fun invoke(re: Number): ComplexDouble {
91-
return if (fitsInFloat(re.toDouble()))
92-
ComplexDouble32(re.toDouble(), 0.0)
93-
else
94-
ComplexDouble64(re.toDouble(), 0.0)
95-
}
96-
9777
/**
9878
* Represents a [ComplexDouble] number with 1.0 real part and 0f imaginary part.
9979
*/
10080
public val one: ComplexDouble
101-
get() = ComplexDouble32(1.0, 0.0)
81+
get() = ComplexDouble(1.0, 0.0)
10282

10383
/**
10484
* Represents a [ComplexDouble] number with real and imaginary parts set to 0.0.
10585
*/
10686
public val zero: ComplexDouble
107-
get() = ComplexDouble32(0.0, 0.0)
87+
get() = ComplexDouble(0.0, 0.0)
10888

10989
/**
11090
* Represents a not-a-number (NaN) value in complex floating point arithmetic.
11191
*/
11292
public val NaN: ComplexDouble
113-
get() = ComplexDouble64(Double.NaN, Double.NaN)
93+
get() = ComplexDouble(Double.NaN, Double.NaN)
11494
}
11595

11696
/**
@@ -452,64 +432,9 @@ public sealed interface ComplexDouble : Complex {
452432
* @return the imaginary part of the complex number as a Double value.
453433
*/
454434
public operator fun component2(): Double = im
455-
}
456-
457-
/**
458-
* ComplexDouble64 represents a double-precision 128-bit complex number,
459-
* which implements the interface `ComplexDouble`.
460-
*
461-
* @property re the real part of the complex number.
462-
* @property im the imaginary part of the complex number.
463-
* @constructor creates an instance of ComplexDouble64.
464-
*/
465-
public class ComplexDouble64 internal constructor(
466-
public override val re: Double, public override val im: Double
467-
) : ComplexDouble {
468-
469-
override fun equals(other: Any?): Boolean = when {
470-
this === other -> true
471-
other is ComplexDouble -> re == other.re && im == other.im
472-
else -> false
473-
}
474-
475-
override fun hashCode(): Int = 31 * re.toBits().hashCode() + im.toBits().hashCode()
476-
477-
override fun toString(): String = "$re+($im)i"
478-
}
479-
480-
/**
481-
* Represents a complex number of single-precision real and imaginary parts.
482-
*
483-
* @param number The number representing the complex number as a Long value
484-
* @property re the real part of the complex number.
485-
* @property im the imaginary part of the complex number.
486-
*/
487-
@JvmInline
488-
public value class ComplexDouble32 internal constructor(private val number: Long) : ComplexDouble {
489-
override val re: Double
490-
get() = Float.fromBits((number shr 32).toInt()).toDouble()
491-
492-
override val im: Double
493-
get() = Float.fromBits(number.toInt()).toDouble()
494-
495-
internal constructor(re: Double, im: Double) : this(Complex.convertComplexFloatToLong(re.toFloat(), im.toFloat()))
496-
497-
// TODO
498-
// "https://youtrack.jetbrains.com/issue/KT-24874/Support-custom-equals-and-hashCode-for-value-classes"
499-
internal fun eq(other: ComplexDouble32): Boolean = when {
500-
number == other.number -> true
501-
else -> re == other.re && im == other.im
502-
}
503-
504-
internal fun hash(): Int = 31 * number.hashCode()
505435

506-
// override fun equals(other: Any?): Boolean = when {
507-
// this === other -> true
508-
// other is ComplexDouble -> re == other.re && im == other.im
509-
// else -> false
510-
// }
511-
//
512-
// override fun hashCode(): Int = 31 * re.toBits().hashCode() + im.toBits().hashCode()
436+
// TODO("https://youtrack.jetbrains.com/issue/KT-24874/Support-custom-equals-and-hashCode-for-value-classes")
437+
public fun eq(other: Any): Boolean
513438

514-
override fun toString(): String = "$re+($im)i"
439+
public fun hash(): Int
515440
}

multik-core/src/commonMain/kotlin/org/jetbrains/kotlinx/multik/ndarray/data/DataType.kt

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
package org.jetbrains.kotlinx.multik.ndarray.data
66

77
import org.jetbrains.kotlinx.multik.ndarray.complex.ComplexDouble
8-
import org.jetbrains.kotlinx.multik.ndarray.complex.ComplexDouble32
9-
import org.jetbrains.kotlinx.multik.ndarray.complex.ComplexDouble64
108
import org.jetbrains.kotlinx.multik.ndarray.complex.ComplexFloat
119
import org.jetbrains.kotlinx.multik.ndarray.data.DataType.*
1210
import kotlin.reflect.KClass
1311

12+
@PublishedApi
13+
internal expect inline fun <T : Any> dataTypeOf(type: KClass<out T>): DataType
14+
1415
/**
1516
* Describes the type of elements stored in a [NDArray].
1617
*
@@ -66,39 +67,16 @@ public enum class DataType(public val nativeCode: Int, public val itemSize: Int,
6667
/**
6768
* Returns [DataType] by class of [element].
6869
*/
69-
@Suppress( "nothing_to_inline")
7070
public inline fun <T> of(element: T): DataType {
7171
element ?: throw IllegalStateException("Element is null cannot find type")
72-
return when (element!!::class) {
73-
Byte::class -> ByteDataType
74-
Short::class -> ShortDataType
75-
Int::class -> IntDataType
76-
Long::class -> LongDataType
77-
Float::class -> FloatDataType
78-
Double::class -> DoubleDataType
79-
ComplexFloat::class -> ComplexFloatDataType
80-
ComplexDouble64::class -> ComplexDoubleDataType
81-
ComplexDouble32::class -> ComplexDoubleDataType
82-
else -> throw IllegalStateException("One of the primitive types was expected, " +
83-
"got ${element!!::class.simpleName}")
84-
}
72+
return dataTypeOf(element!!::class)
8573
}
8674

8775

8876
/**
8977
* Returns [DataType] by [KClass] of [type]. [T] is `reified` type.
9078
*/
91-
public inline fun <reified T : Any> ofKClass(type: KClass<out T>): DataType = when (type) {
92-
Byte::class -> ByteDataType
93-
Short::class -> ShortDataType
94-
Int::class -> IntDataType
95-
Long::class -> LongDataType
96-
Float::class -> FloatDataType
97-
Double::class -> DoubleDataType
98-
ComplexFloat::class -> ComplexFloatDataType
99-
ComplexDouble::class -> ComplexDoubleDataType
100-
else -> throw IllegalStateException("One of the primitive types was expected, got ${type.simpleName}")
101-
}
79+
public inline fun <T : Any> ofKClass(type: KClass<out T>): DataType = dataTypeOf(type)
10280
}
10381

10482
override fun toString(): String {

multik-core/src/commonMain/kotlin/org/jetbrains/kotlinx/multik/ndarray/data/NDArray.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
package org.jetbrains.kotlinx.multik.ndarray.data
66

7-
import org.jetbrains.kotlinx.multik.ndarray.complex.ComplexDouble32
7+
import org.jetbrains.kotlinx.multik.ndarray.complex.ComplexDouble
88
import org.jetbrains.kotlinx.multik.ndarray.complex.ComplexFloat
99
import org.jetbrains.kotlinx.multik.ndarray.operations.concatenate
1010

@@ -300,8 +300,7 @@ public class NDArray<T, D : Dimension> constructor(
300300

301301
val thIt = this.iterator()
302302
val othIt = other.iterator()
303-
// TODO
304-
// workaround for value classes: ComplexFloat and ComplexDouble32
303+
// TODO(workaround for value classes: ComplexFloat and ComplexDouble)
305304
// "https://youtrack.jetbrains.com/issue/KT-24874/Support-custom-equals-and-hashCode-for-value-classes"
306305
while (thIt.hasNext() && othIt.hasNext()) {
307306
val left = thIt.next()
@@ -312,7 +311,7 @@ public class NDArray<T, D : Dimension> constructor(
312311
return false
313312
}
314313

315-
left is ComplexDouble32 && right is ComplexDouble32 -> {
314+
left is ComplexDouble && right is ComplexDouble -> {
316315
if (!(left.eq(right)))
317316
return false
318317
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.jetbrains.kotlinx.multik.ndarray.complex
2+
3+
/**
4+
* Creates a [ComplexDouble] with the given real and imaginary values in floating-point format.
5+
*
6+
* @param re the real value of the complex number in double format.
7+
* @param im the imaginary value of the complex number in double format.
8+
*/
9+
public actual fun ComplexDouble(re: Double, im: Double): ComplexDouble = JsComplexDouble(re, im)
10+
11+
/**
12+
* Creates a [ComplexDouble] with the given real and imaginary values in number format.
13+
*
14+
* @param re the real value of the complex number in number format.
15+
* @param im the imaginary value of the complex number in number format.
16+
*/
17+
public actual fun ComplexDouble(re: Number, im: Number): ComplexDouble = ComplexDouble(re.toDouble(), im.toDouble())
18+
19+
/**
20+
* Represents a complex number with double precision.
21+
*
22+
* @property re The real part of the complex number.
23+
* @property im The imaginary part of the complex number.
24+
*/
25+
public class JsComplexDouble internal constructor(
26+
public override val re: Double, public override val im: Double
27+
) : ComplexDouble {
28+
29+
override fun eq(other: Any): Boolean = equals(other)
30+
31+
override fun hash(): Int = hashCode()
32+
33+
override fun equals(other: Any?): Boolean = when {
34+
this === other -> true
35+
other is ComplexDouble -> re == other.re && im == other.im
36+
else -> false
37+
}
38+
39+
override fun hashCode(): Int = 31 * re.toBits().hashCode() + im.toBits().hashCode()
40+
41+
override fun toString(): String = "$re+($im)i"
42+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.jetbrains.kotlinx.multik.ndarray.data
2+
3+
import org.jetbrains.kotlinx.multik.ndarray.complex.ComplexDouble
4+
import org.jetbrains.kotlinx.multik.ndarray.complex.ComplexFloat
5+
import org.jetbrains.kotlinx.multik.ndarray.complex.JsComplexDouble
6+
import org.jetbrains.kotlinx.multik.ndarray.data.DataType.*
7+
import kotlin.reflect.KClass
8+
9+
@PublishedApi
10+
@Suppress("NOTHING_TO_INLINE")
11+
internal actual inline fun <T : Any> dataTypeOf(type: KClass<out T>): DataType =
12+
when (type) {
13+
Byte::class -> ByteDataType
14+
Short::class -> ShortDataType
15+
Int::class -> IntDataType
16+
Long::class -> LongDataType
17+
Float::class -> FloatDataType
18+
Double::class -> DoubleDataType
19+
ComplexFloat::class -> ComplexFloatDataType
20+
ComplexDouble::class, JsComplexDouble::class -> ComplexDoubleDataType
21+
else -> throw IllegalStateException("One of the primitive types was expected, got ${type.simpleName}")
22+
}

0 commit comments

Comments
 (0)