forked from kscience/kmath
Prototype of generic complex numbers
This commit is contained in:
parent
bcc666d19e
commit
140a426a04
@ -20,9 +20,9 @@ import java.math.BigInteger
|
||||
internal class BigIntBenchmark {
|
||||
|
||||
val kmNumber = BigIntField.number(Int.MAX_VALUE)
|
||||
val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE)
|
||||
val jvmNumber = JBigIntegerRing.number(Int.MAX_VALUE)
|
||||
val largeKmNumber = BigIntField { number(11).pow(100_000U) }
|
||||
val largeJvmNumber: BigInteger = JBigIntegerField { number(11).pow(100_000) }
|
||||
val largeJvmNumber: BigInteger = JBigIntegerRing { number(11).pow(100_000) }
|
||||
val bigExponent = 50_000
|
||||
|
||||
@Benchmark
|
||||
@ -31,7 +31,7 @@ internal class BigIntBenchmark {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun jvmAdd(blackhole: Blackhole) = JBigIntegerField {
|
||||
fun jvmAdd(blackhole: Blackhole) = JBigIntegerRing {
|
||||
blackhole.consume(jvmNumber + jvmNumber + jvmNumber)
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ internal class BigIntBenchmark {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun jvmAddLarge(blackhole: Blackhole) = JBigIntegerField {
|
||||
fun jvmAddLarge(blackhole: Blackhole) = JBigIntegerRing {
|
||||
blackhole.consume(largeJvmNumber + largeJvmNumber + largeJvmNumber)
|
||||
}
|
||||
|
||||
@ -56,12 +56,12 @@ internal class BigIntBenchmark {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun jvmMultiply(blackhole: Blackhole) = JBigIntegerField {
|
||||
fun jvmMultiply(blackhole: Blackhole) = JBigIntegerRing {
|
||||
blackhole.consume(jvmNumber * jvmNumber * jvmNumber)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerField {
|
||||
fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerRing {
|
||||
blackhole.consume(largeJvmNumber*largeJvmNumber)
|
||||
}
|
||||
|
||||
@ -71,27 +71,27 @@ internal class BigIntBenchmark {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun jvmPower(blackhole: Blackhole) = JBigIntegerField {
|
||||
fun jvmPower(blackhole: Blackhole) = JBigIntegerRing {
|
||||
blackhole.consume(jvmNumber.pow(bigExponent))
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun kmParsing16(blackhole: Blackhole) = JBigIntegerField {
|
||||
fun kmParsing16(blackhole: Blackhole) = JBigIntegerRing {
|
||||
blackhole.consume("0x7f57ed8b89c29a3b9a85c7a5b84ca3929c7b7488593".parseBigInteger())
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun kmParsing10(blackhole: Blackhole) = JBigIntegerField {
|
||||
fun kmParsing10(blackhole: Blackhole) = JBigIntegerRing {
|
||||
blackhole.consume("236656783929183747565738292847574838922010".parseBigInteger())
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun jvmParsing10(blackhole: Blackhole) = JBigIntegerField {
|
||||
fun jvmParsing10(blackhole: Blackhole) = JBigIntegerRing {
|
||||
blackhole.consume("236656783929183747565738292847574838922010".toBigInteger(10))
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun jvmParsing16(blackhole: Blackhole) = JBigIntegerField {
|
||||
fun jvmParsing16(blackhole: Blackhole) = JBigIntegerRing {
|
||||
blackhole.consume("7f57ed8b89c29a3b9a85c7a5b84ca3929c7b7488593".toBigInteger(16))
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import space.kscience.kmath.structures.MutableBuffer
|
||||
internal class BufferBenchmark {
|
||||
@Benchmark
|
||||
fun genericDoubleBufferReadWrite() {
|
||||
val buffer = DoubleBuffer(size) { it.toDouble() }
|
||||
val buffer = DoubleBuffer(size, Int::toDouble)
|
||||
|
||||
(0 until size).forEach {
|
||||
buffer[it]
|
||||
@ -26,7 +26,8 @@ internal class BufferBenchmark {
|
||||
|
||||
@Benchmark
|
||||
fun complexBufferReadWrite() {
|
||||
val buffer = MutableBuffer.complex(size / 2) { Complex(it.toDouble(), -it.toDouble()) }
|
||||
val buffer =
|
||||
MutableBuffer.complex(MutableBuffer.Companion::double, size / 2) { Complex(it.toDouble(), -it.toDouble()) }
|
||||
|
||||
(0 until size / 2).forEach {
|
||||
buffer[it]
|
||||
|
@ -47,7 +47,7 @@ internal class NDFieldBenchmark {
|
||||
private const val dim = 1000
|
||||
private const val n = 100
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val specializedField = AlgebraND.real(dim, dim)
|
||||
private val specializedField = AlgebraND.double(dim, dim)
|
||||
private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import org.jetbrains.bio.viktor.F64Array
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.auto
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.nd.double
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.viktor.ViktorNDField
|
||||
|
||||
@ -60,7 +60,7 @@ internal class ViktorBenchmark {
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val realField = AlgebraND.real(dim, dim)
|
||||
private val realField = AlgebraND.double(dim, dim)
|
||||
private val viktorField = ViktorNDField(dim, dim)
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import kotlinx.benchmark.State
|
||||
import org.jetbrains.bio.viktor.F64Array
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.auto
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.nd.double
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.viktor.ViktorFieldND
|
||||
|
||||
@ -52,7 +52,7 @@ internal class ViktorLogBenchmark {
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val realNdField = AlgebraND.real(dim, dim)
|
||||
private val realNdField = AlgebraND.double(dim, dim)
|
||||
private val viktorField = ViktorFieldND(intArrayOf(dim, dim))
|
||||
}
|
||||
}
|
||||
|
@ -8,16 +8,17 @@ package space.kscience.kmath.operations
|
||||
import space.kscience.kmath.complex.Complex
|
||||
import space.kscience.kmath.complex.complex
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.double
|
||||
|
||||
fun main() {
|
||||
// 2d element
|
||||
val element = AlgebraND.complex(2, 2).produce { (i, j) ->
|
||||
val element = AlgebraND.double(2, 2).complex().produce { (i, j) ->
|
||||
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
||||
}
|
||||
println(element)
|
||||
|
||||
// 1d element operation
|
||||
val result = with(AlgebraND.complex(8)) {
|
||||
val result = with(AlgebraND.double(8).complex()) {
|
||||
val a = produce { (it) -> i * it - it.toDouble() }
|
||||
val b = 3
|
||||
val c = Complex(1.0, 1.0)
|
||||
|
@ -12,19 +12,19 @@ import space.kscience.kmath.linear.transpose
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.as2D
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.nd.double
|
||||
import space.kscience.kmath.operations.*
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
fun main() {
|
||||
val dim = 1000
|
||||
val n = 1000
|
||||
|
||||
val realField = AlgebraND.real(dim, dim)
|
||||
val complexField: ComplexFieldND = AlgebraND.complex(dim, dim)
|
||||
val doubleField = AlgebraND.double(dim, dim)
|
||||
val complexField = doubleField.complex()
|
||||
|
||||
val realTime = measureTimeMillis {
|
||||
realField {
|
||||
doubleField {
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) {
|
||||
res += 1.0
|
||||
@ -36,9 +36,9 @@ fun main() {
|
||||
|
||||
val complexTime = measureTimeMillis {
|
||||
complexField {
|
||||
var res: StructureND<Complex> = one
|
||||
var res: StructureND<Complex<Double>> = one
|
||||
repeat(n) {
|
||||
res += 1.0
|
||||
res += Complex(1.0, 0.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,18 +48,16 @@ fun main() {
|
||||
|
||||
fun complexExample() {
|
||||
//Create a context for 2-d structure with complex values
|
||||
ComplexField {
|
||||
nd(4, 8) {
|
||||
//a constant real-valued structure
|
||||
val x = one * 2.5
|
||||
operator fun Number.plus(other: Complex) = Complex(this.toDouble() + other.re, other.im)
|
||||
//a structure generator specific to this context
|
||||
val matrix = produce { (k, l) -> k + l * i }
|
||||
//Perform sum
|
||||
val sum = matrix + x + 1.0
|
||||
AlgebraND.double(4, 8).complex().run {
|
||||
//a constant real-valued structure
|
||||
val x = one * 2.5
|
||||
operator fun Number.plus(other: Complex<Double>) = Complex(toDouble() + other.re, other.im)
|
||||
//a structure generator specific to this context
|
||||
val matrix = produce { (k, l) -> k + l * i }
|
||||
//Perform sum
|
||||
val sum = matrix + x + Complex(1.0,0.0)
|
||||
|
||||
//Represent the sum as 2d-structure and transpose
|
||||
sum.as2D().transpose()
|
||||
}
|
||||
//Represent the sum as 2d-structure and transpose
|
||||
sum.as2D().transpose()
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,8 @@ fun main() {
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
// specialized nd-field for Double. It works as generic Double field as well.
|
||||
val realField = AlgebraND.real(dim, dim)
|
||||
// specialized nd-field for Double. It works as generic Double field as well
|
||||
val realField = AlgebraND.double(dim, dim)
|
||||
//A generic boxing field. It should be used for objects, not primitives.
|
||||
val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||
// Nd4j specialized field.
|
||||
|
@ -6,6 +6,7 @@
|
||||
package space.kscience.kmath.ast
|
||||
|
||||
import space.kscience.kmath.complex.Complex
|
||||
import space.kscience.kmath.complex.ComplexDoubleField
|
||||
import space.kscience.kmath.complex.ComplexField
|
||||
import space.kscience.kmath.expressions.evaluate
|
||||
import space.kscience.kmath.operations.Algebra
|
||||
@ -17,15 +18,15 @@ internal class TestParser {
|
||||
@Test
|
||||
fun evaluateParsedMst() {
|
||||
val mst = "2+2*(2+2)".parseMath()
|
||||
val res = ComplexField.evaluate(mst)
|
||||
val res = ComplexDoubleField.evaluate(mst)
|
||||
assertEquals(Complex(10.0, 0.0), res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun evaluateMstSymbol() {
|
||||
val mst = "i".parseMath()
|
||||
val res = ComplexField.evaluate(mst)
|
||||
assertEquals(ComplexField.i, res)
|
||||
val res = ComplexDoubleField.evaluate(mst)
|
||||
assertEquals(ComplexDoubleField.i, res)
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,12 +15,11 @@ import space.kscience.kmath.streaming.spread
|
||||
import space.kscience.kmath.structures.*
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Streaming and buffer transformations
|
||||
*/
|
||||
public object Transformations {
|
||||
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
|
||||
private fun Buffer<Complex<Double>>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
|
||||
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
|
||||
|
||||
private fun Buffer<Double>.asArray() = if (this is DoubleBuffer) {
|
||||
@ -40,14 +39,14 @@ public object Transformations {
|
||||
public fun fourier(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Complex, Complex> = {
|
||||
): SuspendBufferTransform<Complex<Double>, Complex<Double>> = {
|
||||
FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun realFourier(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Complex> = {
|
||||
): SuspendBufferTransform<Double, Complex<Double>> = {
|
||||
FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
@ -76,10 +75,10 @@ public object Transformations {
|
||||
* Process given [Flow] with commons-math fft transformation
|
||||
*/
|
||||
@FlowPreview
|
||||
public fun Flow<Buffer<Complex>>.FFT(
|
||||
public fun Flow<Buffer<Complex<Double>>>.FFT(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Buffer<Complex>> {
|
||||
): Flow<Buffer<Complex<Double>>> {
|
||||
val transform = Transformations.fourier(normalization, direction)
|
||||
return map { transform(it) }
|
||||
}
|
||||
@ -89,7 +88,7 @@ public fun Flow<Buffer<Complex>>.FFT(
|
||||
public fun Flow<Buffer<Double>>.FFT(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Buffer<Complex>> {
|
||||
): Flow<Buffer<Complex<Double>>> {
|
||||
val transform = Transformations.realFourier(normalization, direction)
|
||||
return map(transform)
|
||||
}
|
||||
@ -103,10 +102,10 @@ public fun Flow<Double>.FFT(
|
||||
bufferSize: Int = Int.MAX_VALUE,
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread()
|
||||
): Flow<Complex<Double>> = chunked(bufferSize).FFT(normalization, direction).spread()
|
||||
|
||||
/**
|
||||
* Map a complex flow into real flow by taking real part of each number
|
||||
*/
|
||||
@FlowPreview
|
||||
public fun Flow<Complex>.real(): Flow<Double> = map { it.re }
|
||||
public fun Flow<Complex<Double>>.real(): Flow<Double> = map { it.re }
|
||||
|
@ -5,223 +5,248 @@
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.memory.MemoryReader
|
||||
import space.kscience.kmath.memory.MemorySpec
|
||||
import space.kscience.kmath.memory.MemoryWriter
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.ExtendedField
|
||||
import space.kscience.kmath.operations.Norm
|
||||
import space.kscience.kmath.operations.NumbersAddOperations
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.MemoryBuffer
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
import space.kscience.kmath.structures.MutableMemoryBuffer
|
||||
import kotlin.math.*
|
||||
import space.kscience.kmath.operations.*
|
||||
import kotlin.js.JsName
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
/**
|
||||
* This complex's conjugate.
|
||||
* Represents generic complex value consisting of real and imaginary part.
|
||||
*
|
||||
* @param T the type of components.
|
||||
* @property re The real component.
|
||||
* @property im The imaginary component.
|
||||
*/
|
||||
public val Complex.conjugate: Complex
|
||||
get() = Complex(re, -im)
|
||||
public data class Complex<out T : Any>(public val re: T, public val im: T) {
|
||||
/**
|
||||
* Converts this complex number to string formatted like `[re] + i * [im]`.
|
||||
*/
|
||||
override fun toString(): String = "$re + i * $im"
|
||||
}
|
||||
|
||||
/**
|
||||
* This complex's reciprocal.
|
||||
* The algebra of [Complex].
|
||||
*
|
||||
* @param T the type of components.
|
||||
* @property algebra the algebra over [T].
|
||||
*/
|
||||
public val Complex.reciprocal: Complex
|
||||
get() {
|
||||
val scale = re * re + im * im
|
||||
return Complex(re / scale, -im / scale)
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute value of complex number.
|
||||
*/
|
||||
public val Complex.r: Double
|
||||
get() = sqrt(re * re + im * im)
|
||||
|
||||
/**
|
||||
* An angle between vector represented by complex number and X axis.
|
||||
*/
|
||||
public val Complex.theta: Double
|
||||
get() = atan(im / re)
|
||||
|
||||
private val PI_DIV_2 = Complex(PI / 2, 0)
|
||||
|
||||
/**
|
||||
* A field of [Complex].
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, NumbersAddOperations<Complex>,
|
||||
ScaleOperations<Complex> {
|
||||
override val zero: Complex = 0.0.toComplex()
|
||||
override val one: Complex = 1.0.toComplex()
|
||||
|
||||
public open class ComplexAlgebra<T : Any>(public open val algebra: NumericAlgebra<T>) : NumericAlgebra<Complex<T>> {
|
||||
/**
|
||||
* The imaginary unit.
|
||||
*/
|
||||
public val i: Complex by lazy { Complex(0.0, 1.0) }
|
||||
|
||||
override fun Complex.unaryMinus(): Complex = Complex(-re, -im)
|
||||
|
||||
override fun number(value: Number): Complex = Complex(value.toDouble(), 0.0)
|
||||
|
||||
override fun scale(a: Complex, value: Double): Complex = Complex(a.re * value, a.im * value)
|
||||
|
||||
override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im)
|
||||
// override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble())
|
||||
|
||||
override fun multiply(a: Complex, b: Complex): Complex =
|
||||
Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re)
|
||||
|
||||
override fun divide(a: Complex, b: Complex): Complex = when {
|
||||
abs(b.im) < abs(b.re) -> {
|
||||
val wr = b.im / b.re
|
||||
val wd = b.re + wr * b.im
|
||||
|
||||
if (wd.isNaN() || wd == 0.0)
|
||||
throw ArithmeticException("Division by zero or infinity")
|
||||
else
|
||||
Complex((a.re + a.im * wr) / wd, (a.im - a.re * wr) / wd)
|
||||
}
|
||||
|
||||
b.im == 0.0 -> throw ArithmeticException("Division by zero")
|
||||
|
||||
else -> {
|
||||
val wr = b.re / b.im
|
||||
val wd = b.im + wr * b.re
|
||||
|
||||
if (wd.isNaN() || wd == 0.0)
|
||||
throw ArithmeticException("Division by zero or infinity")
|
||||
else
|
||||
Complex((a.re * wr + a.im) / wd, (a.im * wr - a.re) / wd)
|
||||
}
|
||||
public open val i: Complex<T> by lazy {
|
||||
algebra { Complex(number(0), number(1)) }
|
||||
}
|
||||
|
||||
override operator fun Complex.div(k: Number): Complex = Complex(re / k.toDouble(), im / k.toDouble())
|
||||
override fun number(value: Number): Complex<T> =
|
||||
algebra { Complex(algebra.number(value), algebra.number(0)) }
|
||||
|
||||
override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2.0
|
||||
override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2.0
|
||||
override fun bindSymbol(value: String): Complex<T> = if (value == "i") i else super.bindSymbol(value)
|
||||
}
|
||||
|
||||
override fun tan(arg: Complex): Complex {
|
||||
/**
|
||||
* The group of [Complex].
|
||||
*
|
||||
* @param T the type of components.
|
||||
*/
|
||||
public open class ComplexGroup<T : Any, out A>(override val algebra: A) : ComplexAlgebra<T>(algebra),
|
||||
Group<Complex<T>> where A : NumericAlgebra<T>, A : Group<T> {
|
||||
override val zero: Complex<T> by lazy {
|
||||
algebra { Complex(zero, zero) }
|
||||
}
|
||||
|
||||
/**
|
||||
* This complex's conjugate.
|
||||
*/
|
||||
public val Complex<T>.conjugate: Complex<T>
|
||||
get() = Complex(re, algebra { -im })
|
||||
|
||||
override fun add(a: Complex<T>, b: Complex<T>): Complex<T> = algebra { Complex(a.re + b.re, a.im + b.im) }
|
||||
|
||||
override fun Complex<T>.unaryMinus(): Complex<T> = algebra { Complex(-re, -im) }
|
||||
|
||||
@JsName("unaryMinus_T")
|
||||
public operator fun T.unaryMinus(): Complex<T> = algebra { Complex(-this@unaryMinus, zero) }
|
||||
|
||||
@JsName("unaryPlus_T")
|
||||
public operator fun T.unaryPlus(): Complex<T> = algebra { Complex(this@unaryPlus, zero) }
|
||||
|
||||
public operator fun T.plus(b: Complex<T>): Complex<T> = add(+this, b)
|
||||
public operator fun Complex<T>.plus(b: T): Complex<T> = add(this, +b)
|
||||
public operator fun T.minus(b: Complex<T>): Complex<T> = add(+this, -b)
|
||||
public operator fun Complex<T>.minus(b: T): Complex<T> = add(this, -b)
|
||||
}
|
||||
|
||||
/**
|
||||
* The ring of [Complex].
|
||||
*
|
||||
* @param T the type of components.
|
||||
*/
|
||||
public open class ComplexRing<T : Any, out A>(override val algebra: A) : ComplexGroup<T, A>(algebra),
|
||||
Ring<Complex<T>> where A : NumericAlgebra<T>, A : Ring<T> {
|
||||
override val one: Complex<T> by lazy {
|
||||
algebra { Complex(one, zero) }
|
||||
}
|
||||
|
||||
override val i: Complex<T> by lazy {
|
||||
algebra { Complex(zero, one) }
|
||||
}
|
||||
|
||||
override fun multiply(a: Complex<T>, b: Complex<T>): Complex<T> =
|
||||
algebra { Complex(a.re * b.re - a.im * b.im, a.im * b.re + a.re * b.im) }
|
||||
|
||||
public operator fun T.times(b: Complex<T>): Complex<T> = multiply(+this, b)
|
||||
public operator fun Complex<T>.times(b: T): Complex<T> = multiply(this, +b)
|
||||
}
|
||||
|
||||
/**
|
||||
* [ComplexRing] instance for [ByteRing].
|
||||
*/
|
||||
public val ComplexByteRing: ComplexRing<Byte, ByteRing> = ComplexRing(ByteRing)
|
||||
|
||||
/**
|
||||
* [ComplexRing] instance for [ShortRing].
|
||||
*/
|
||||
public val ComplexShortRing: ComplexRing<Short, ShortRing> = ComplexRing(ShortRing)
|
||||
|
||||
/**
|
||||
* [ComplexRing] instance for [IntRing].
|
||||
*/
|
||||
public val ComplexIntRing: ComplexRing<Int, IntRing> = ComplexRing(IntRing)
|
||||
|
||||
/**
|
||||
* [ComplexRing] instance for [LongRing].
|
||||
*/
|
||||
public val ComplexLongRing: ComplexRing<Long, LongRing> = ComplexRing(LongRing)
|
||||
|
||||
/**
|
||||
* The field of [Complex].
|
||||
*/
|
||||
public open class ComplexField<T : Any, out A>(override val algebra: A) : ComplexRing<T, A>(algebra),
|
||||
Field<Complex<T>> where A : Field<T> {
|
||||
/**
|
||||
* This complex's reciprocal.
|
||||
*/
|
||||
public val Complex<T>.reciprocal: Complex<T>
|
||||
get() = algebra {
|
||||
val scale = re * re + im * im
|
||||
Complex(re / scale, -im / scale)
|
||||
}
|
||||
|
||||
override fun divide(a: Complex<T>, b: Complex<T>): Complex<T> = a * b.reciprocal
|
||||
|
||||
override fun number(value: Number): Complex<T> = super<ComplexRing>.number(value)
|
||||
|
||||
override fun scale(a: Complex<T>, value: Double): Complex<T> =
|
||||
algebra { Complex(a.re * value, a.im * value) }
|
||||
|
||||
override operator fun Complex<T>.div(k: Number): Complex<T> =
|
||||
algebra { Complex(re / k.toDouble(), im / k.toDouble()) }
|
||||
|
||||
public operator fun T.div(b: Complex<T>): Complex<T> = divide(+this, b)
|
||||
public operator fun Complex<T>.div(b: T): Complex<T> = divide(this, +b)
|
||||
|
||||
@JsName("scale_T")
|
||||
public fun scale(a: T, value: Double): Complex<T> = scale(+a, value)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [ComplexRing] instance for [BigIntField].
|
||||
*/
|
||||
public val ComplexBigIntField: ComplexField<BigInt, BigIntField> = ComplexField(BigIntField)
|
||||
|
||||
|
||||
/**
|
||||
* The extended field of Complex.
|
||||
*/
|
||||
public open class ComplexExtendedField<T : Any, out A>(override val algebra: A) : ComplexField<T, A>(algebra),
|
||||
ExtendedField<Complex<T>>, Norm<Complex<T>, T> where A : ExtendedField<T> {
|
||||
private val two by lazy { one + one }
|
||||
|
||||
/**
|
||||
* The *r* component of the polar form of this number.
|
||||
*/
|
||||
public val Complex<T>.r: T
|
||||
get() = norm(this)
|
||||
|
||||
/**
|
||||
* The *θ* component of the polar form of this number.
|
||||
*/
|
||||
public val Complex<T>.theta: T
|
||||
get() = algebra { atan(im / re) }
|
||||
|
||||
override fun bindSymbol(value: String): Complex<T> =
|
||||
if (value == "i") i else super<ExtendedField>.bindSymbol(value)
|
||||
|
||||
override fun sin(arg: Complex<T>): Complex<T> = i * (exp(-i * arg) - exp(i * arg)) / two
|
||||
override fun cos(arg: Complex<T>): Complex<T> = (exp(-i * arg) + exp(i * arg)) / two
|
||||
|
||||
override fun tan(arg: Complex<T>): Complex<T> {
|
||||
val e1 = exp(-i * arg)
|
||||
val e2 = exp(i * arg)
|
||||
return i * (e1 - e2) / (e1 + e2)
|
||||
}
|
||||
|
||||
override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg)
|
||||
override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg)
|
||||
override fun asin(arg: Complex<T>): Complex<T> = -i * ln(sqrt(one - (arg * arg)) + i * arg)
|
||||
override fun acos(arg: Complex<T>): Complex<T> =
|
||||
(pi / two) + i * ln(sqrt(one - (arg * arg)) + i * arg)
|
||||
|
||||
override fun atan(arg: Complex): Complex {
|
||||
override fun atan(arg: Complex<T>): Complex<T> = algebra {
|
||||
val iArg = i * arg
|
||||
return i * (ln(1 - iArg) - ln(1 + iArg)) / 2
|
||||
return i * (ln(this@ComplexExtendedField.one - iArg) - ln(this@ComplexExtendedField.one + iArg)) / 2
|
||||
}
|
||||
|
||||
override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0)
|
||||
arg.re.pow(pow.toDouble()).toComplex()
|
||||
else
|
||||
exp(pow * ln(arg))
|
||||
override fun power(arg: Complex<T>, pow: Number): Complex<T> = algebra {
|
||||
if (arg.im == 0.0)
|
||||
Complex(arg.re.pow(pow.toDouble()), algebra.zero)
|
||||
else
|
||||
exp(pow * ln(arg))
|
||||
}
|
||||
|
||||
override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im))
|
||||
override fun exp(arg: Complex<T>): Complex<T> =
|
||||
Complex(algebra.exp(arg.re), algebra.zero) * Complex(algebra.cos(arg.im), algebra.sin(arg.im))
|
||||
|
||||
override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re)
|
||||
override fun ln(arg: Complex<T>): Complex<T> = algebra { Complex(ln(norm(arg)), atan(arg.im / arg.re)) }
|
||||
override fun norm(arg: Complex<T>): T = algebra { sqrt(arg.re * arg.re + arg.im * arg.im) }
|
||||
|
||||
/**
|
||||
* Adds complex number to real one.
|
||||
*
|
||||
* @receiver the augend.
|
||||
* @param c the addend.
|
||||
* @return the sum.
|
||||
*/
|
||||
public operator fun Double.plus(c: Complex): Complex = add(this.toComplex(), c)
|
||||
@JsName("norm_T_3")
|
||||
@JvmName("norm\$T")
|
||||
public fun norm(arg: T): T = algebra { sqrt(arg * arg) }
|
||||
|
||||
/**
|
||||
* Subtracts complex number from real one.
|
||||
*
|
||||
* @receiver the minuend.
|
||||
* @param c the subtrahend.
|
||||
* @return the difference.
|
||||
*/
|
||||
public operator fun Double.minus(c: Complex): Complex = add(this.toComplex(), -c)
|
||||
@JsName("sin_T")
|
||||
public fun sin(arg: T): Complex<T> = sin(+arg)
|
||||
|
||||
/**
|
||||
* Adds real number to complex one.
|
||||
*
|
||||
* @receiver the augend.
|
||||
* @param d the addend.
|
||||
* @return the sum.
|
||||
*/
|
||||
public operator fun Complex.plus(d: Double): Complex = d + this
|
||||
@JsName("cos_T")
|
||||
public fun cos(arg: T): Complex<T> = cos(+arg)
|
||||
|
||||
/**
|
||||
* Subtracts real number from complex one.
|
||||
*
|
||||
* @receiver the minuend.
|
||||
* @param d the subtrahend.
|
||||
* @return the difference.
|
||||
*/
|
||||
public operator fun Complex.minus(d: Double): Complex = add(this, -d.toComplex())
|
||||
@JsName("tan_T")
|
||||
public fun tan(arg: T): Complex<T> = tan(+arg)
|
||||
|
||||
/**
|
||||
* Multiplies real number by complex one.
|
||||
*
|
||||
* @receiver the multiplier.
|
||||
* @param c the multiplicand.
|
||||
* @receiver the product.
|
||||
*/
|
||||
public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this)
|
||||
@JsName("asin_T")
|
||||
public fun asin(arg: T): Complex<T> = asin(+arg)
|
||||
|
||||
override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
|
||||
@JsName("acos_T")
|
||||
public fun acos(arg: T): Complex<T> = acos(+arg)
|
||||
|
||||
override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null
|
||||
@JsName("atan_T")
|
||||
public fun atan(arg: T): Complex<T> = atan(+arg)
|
||||
|
||||
@JsName("power_T")
|
||||
public fun power(arg: T, pow: Number): Complex<T> = power(+arg, pow)
|
||||
|
||||
@JsName("exp_T")
|
||||
public fun exp(arg: T): Complex<T> = exp(+arg)
|
||||
|
||||
@JsName("ln_T")
|
||||
public fun ln(arg: T): Complex<T> = ln(+arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents `double`-based complex number.
|
||||
*
|
||||
* @property re The real part.
|
||||
* @property im The imaginary part.
|
||||
* [ComplexRing] instance for [DoubleField].
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public data class Complex(val re: Double, val im: Double) {
|
||||
public constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble())
|
||||
public constructor(re: Number) : this(re.toDouble(), 0.0)
|
||||
|
||||
override fun toString(): String = "($re + i * $im)"
|
||||
|
||||
public companion object : MemorySpec<Complex> {
|
||||
override val objectSize: Int
|
||||
get() = 16
|
||||
|
||||
override fun MemoryReader.read(offset: Int): Complex =
|
||||
Complex(readDouble(offset), readDouble(offset + 8))
|
||||
|
||||
override fun MemoryWriter.write(offset: Int, value: Complex) {
|
||||
writeDouble(offset, value.re)
|
||||
writeDouble(offset + 8, value.im)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public val ComplexDoubleField: ComplexExtendedField<Double, DoubleField> = ComplexExtendedField(DoubleField)
|
||||
|
||||
/**
|
||||
* Creates a complex number with real part equal to this real.
|
||||
*
|
||||
* @receiver the real part.
|
||||
* @return the new complex number.
|
||||
* [ComplexRing] instance for [FloatField].
|
||||
*/
|
||||
public fun Number.toComplex(): Complex = Complex(this)
|
||||
|
||||
/**
|
||||
* Creates a new buffer of complex numbers with the specified [size], where each element is calculated by calling the
|
||||
* specified [init] function.
|
||||
*/
|
||||
public inline fun Buffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer<Complex> =
|
||||
MemoryBuffer.create(Complex, size, init)
|
||||
|
||||
/**
|
||||
* Creates a new buffer of complex numbers with the specified [size], where each element is calculated by calling the
|
||||
* specified [init] function.
|
||||
*/
|
||||
public inline fun MutableBuffer.Companion.complex(size: Int, init: (Int) -> Complex): MutableBuffer<Complex> =
|
||||
MutableMemoryBuffer.create(Complex, size, init)
|
||||
public val ComplexFloatField: ComplexExtendedField<Double, DoubleField> = ComplexExtendedField(DoubleField)
|
||||
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.BufferND
|
||||
import space.kscience.kmath.nd.BufferedFieldND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.operations.ExtendedField
|
||||
import space.kscience.kmath.operations.NumbersAddOperations
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
|
||||
/**
|
||||
* An optimized nd-field for complex numbers
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class ComplexFieldND(
|
||||
shape: IntArray,
|
||||
) : BufferedFieldND<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
|
||||
NumbersAddOperations<StructureND<Complex>>,
|
||||
ExtendedField<StructureND<Complex>> {
|
||||
|
||||
override val zero: BufferND<Complex> by lazy { produce { zero } }
|
||||
override val one: BufferND<Complex> by lazy { produce { one } }
|
||||
|
||||
override fun number(value: Number): BufferND<Complex> {
|
||||
val d = value.toComplex() // minimize conversions
|
||||
return produce { d }
|
||||
}
|
||||
|
||||
//
|
||||
// @Suppress("OVERRIDE_BY_INLINE")
|
||||
// override inline fun map(
|
||||
// arg: AbstractNDBuffer<Double>,
|
||||
// transform: DoubleField.(Double) -> Double,
|
||||
// ): RealNDElement {
|
||||
// check(arg)
|
||||
// val array = RealBuffer(arg.strides.linearSize) { offset -> DoubleField.transform(arg.buffer[offset]) }
|
||||
// return BufferedNDFieldElement(this, array)
|
||||
// }
|
||||
//
|
||||
// @Suppress("OVERRIDE_BY_INLINE")
|
||||
// override inline fun produce(initializer: DoubleField.(IntArray) -> Double): RealNDElement {
|
||||
// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
||||
// return BufferedNDFieldElement(this, array)
|
||||
// }
|
||||
//
|
||||
// @Suppress("OVERRIDE_BY_INLINE")
|
||||
// override inline fun mapIndexed(
|
||||
// arg: AbstractNDBuffer<Double>,
|
||||
// transform: DoubleField.(index: IntArray, Double) -> Double,
|
||||
// ): RealNDElement {
|
||||
// check(arg)
|
||||
// return BufferedNDFieldElement(
|
||||
// this,
|
||||
// RealBuffer(arg.strides.linearSize) { offset ->
|
||||
// elementContext.transform(
|
||||
// arg.strides.index(offset),
|
||||
// arg.buffer[offset]
|
||||
// )
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// @Suppress("OVERRIDE_BY_INLINE")
|
||||
// override inline fun combine(
|
||||
// a: AbstractNDBuffer<Double>,
|
||||
// b: AbstractNDBuffer<Double>,
|
||||
// transform: DoubleField.(Double, Double) -> Double,
|
||||
// ): RealNDElement {
|
||||
// check(a, b)
|
||||
// val buffer = RealBuffer(strides.linearSize) { offset ->
|
||||
// elementContext.transform(a.buffer[offset], b.buffer[offset])
|
||||
// }
|
||||
// return BufferedNDFieldElement(this, buffer)
|
||||
// }
|
||||
|
||||
override fun power(arg: StructureND<Complex>, pow: Number): BufferND<Complex> = arg.map { power(it, pow) }
|
||||
|
||||
override fun exp(arg: StructureND<Complex>): BufferND<Complex> = arg.map { exp(it) }
|
||||
|
||||
override fun ln(arg: StructureND<Complex>): BufferND<Complex> = arg.map { ln(it) }
|
||||
|
||||
override fun sin(arg: StructureND<Complex>): BufferND<Complex> = arg.map { sin(it) }
|
||||
override fun cos(arg: StructureND<Complex>): BufferND<Complex> = arg.map { cos(it) }
|
||||
override fun tan(arg: StructureND<Complex>): BufferND<Complex> = arg.map { tan(it) }
|
||||
override fun asin(arg: StructureND<Complex>): BufferND<Complex> = arg.map { asin(it) }
|
||||
override fun acos(arg: StructureND<Complex>): BufferND<Complex> = arg.map { acos(it) }
|
||||
override fun atan(arg: StructureND<Complex>): BufferND<Complex> = arg.map { atan(it) }
|
||||
|
||||
override fun sinh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { sinh(it) }
|
||||
override fun cosh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { cosh(it) }
|
||||
override fun tanh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { tanh(it) }
|
||||
override fun asinh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { asinh(it) }
|
||||
override fun acosh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { acosh(it) }
|
||||
override fun atanh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { atanh(it) }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fast element production using function inlining
|
||||
*/
|
||||
public inline fun BufferedFieldND<Complex, ComplexField>.produceInline(initializer: ComplexField.(Int) -> Complex): BufferND<Complex> {
|
||||
contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) }
|
||||
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) }
|
||||
return BufferND(strides, buffer)
|
||||
}
|
||||
|
||||
|
||||
public fun AlgebraND.Companion.complex(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape)
|
||||
|
||||
/**
|
||||
* Produce a context for n-dimensional operations inside this real field
|
||||
*/
|
||||
public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexFieldND.() -> R): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return ComplexFieldND(shape).action()
|
||||
}
|
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.memory.MemoryReader
|
||||
import space.kscience.kmath.memory.MemorySpec
|
||||
import space.kscience.kmath.memory.MemoryWriter
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.*
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.MemoryBuffer
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
import space.kscience.kmath.structures.MutableMemoryBuffer
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
* This quaternion's conjugate.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public val DoubleQuaternion.conjugate: DoubleQuaternion
|
||||
get() = DoubleQuaternionField { z - x * i - y * j - z * k }
|
||||
|
||||
/**
|
||||
* This quaternion's reciprocal.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public val DoubleQuaternion.reciprocal: DoubleQuaternion
|
||||
get() = DoubleQuaternionField {
|
||||
val n = norm(this@reciprocal)
|
||||
return conjugate / (n * n)
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute value of the quaternion.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public val DoubleQuaternion.r: Double
|
||||
get() = sqrt(w * w + x * x + y * y + z * z)
|
||||
|
||||
/**
|
||||
* A field of [DoubleQuaternion].
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public object DoubleQuaternionField : Field<DoubleQuaternion>, Norm<DoubleQuaternion, DoubleQuaternion>,
|
||||
PowerOperations<DoubleQuaternion>,
|
||||
ExponentialOperations<DoubleQuaternion>, NumbersAddOperations<DoubleQuaternion>, ScaleOperations<DoubleQuaternion> {
|
||||
override val zero: DoubleQuaternion = DoubleQuaternion(0)
|
||||
override val one: DoubleQuaternion = DoubleQuaternion(1)
|
||||
|
||||
/**
|
||||
* The `i` quaternion unit.
|
||||
*/
|
||||
public val i: DoubleQuaternion = DoubleQuaternion(0, 1)
|
||||
|
||||
/**
|
||||
* The `j` quaternion unit.
|
||||
*/
|
||||
public val j: DoubleQuaternion = DoubleQuaternion(0, 0, 1)
|
||||
|
||||
/**
|
||||
* The `k` quaternion unit.
|
||||
*/
|
||||
public val k: DoubleQuaternion = DoubleQuaternion(0, 0, 0, 1)
|
||||
|
||||
override fun add(a: DoubleQuaternion, b: DoubleQuaternion): DoubleQuaternion =
|
||||
DoubleQuaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z)
|
||||
|
||||
override fun scale(a: DoubleQuaternion, value: Double): DoubleQuaternion =
|
||||
DoubleQuaternion(a.w * value, a.x * value, a.y * value, a.z * value)
|
||||
|
||||
override fun multiply(a: DoubleQuaternion, b: DoubleQuaternion): DoubleQuaternion = DoubleQuaternion(
|
||||
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
|
||||
a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
||||
a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
||||
a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
|
||||
)
|
||||
|
||||
override fun divide(a: DoubleQuaternion, b: DoubleQuaternion): DoubleQuaternion {
|
||||
val s = b.w * b.w + b.x * b.x + b.y * b.y + b.z * b.z
|
||||
|
||||
return DoubleQuaternion(
|
||||
(b.w * a.w + b.x * a.x + b.y * a.y + b.z * a.z) / s,
|
||||
(b.w * a.x - b.x * a.w - b.y * a.z + b.z * a.y) / s,
|
||||
(b.w * a.y + b.x * a.z - b.y * a.w - b.z * a.x) / s,
|
||||
(b.w * a.z - b.x * a.y + b.y * a.x - b.z * a.w) / s,
|
||||
)
|
||||
}
|
||||
|
||||
override fun power(arg: DoubleQuaternion, pow: Number): DoubleQuaternion {
|
||||
if (pow is Int) return pwr(arg, pow)
|
||||
if (floor(pow.toDouble()) == pow.toDouble()) return pwr(arg, pow.toInt())
|
||||
return exp(pow * ln(arg))
|
||||
}
|
||||
|
||||
private fun pwr(x: DoubleQuaternion, a: Int): DoubleQuaternion = when {
|
||||
a < 0 -> -(pwr(x, -a))
|
||||
a == 0 -> one
|
||||
a == 1 -> x
|
||||
a == 2 -> pwr2(x)
|
||||
a == 3 -> pwr3(x)
|
||||
a == 4 -> pwr4(x)
|
||||
|
||||
else -> {
|
||||
val x4 = pwr4(x)
|
||||
var y = x4
|
||||
repeat((1 until a / 4).count()) { y *= x4 }
|
||||
if (a % 4 == 3) y *= pwr3(x)
|
||||
if (a % 4 == 2) y *= pwr2(x)
|
||||
if (a % 4 == 1) y *= x
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
private fun pwr2(x: DoubleQuaternion): DoubleQuaternion {
|
||||
val aa = 2 * x.w
|
||||
return DoubleQuaternion(x.w * x.w - (x.x * x.x + x.y * x.y + x.z * x.z), aa * x.x, aa * x.y, aa * x.z)
|
||||
}
|
||||
|
||||
private fun pwr3(x: DoubleQuaternion): DoubleQuaternion {
|
||||
val a2 = x.w * x.w
|
||||
val n1 = x.x * x.x + x.y * x.y + x.z * x.z
|
||||
val n2 = 3.0 * a2 - n1
|
||||
return DoubleQuaternion(x.w * (a2 - 3 * n1), x.x * n2, x.y * n2, x.z * n2)
|
||||
}
|
||||
|
||||
private fun pwr4(x: DoubleQuaternion): DoubleQuaternion {
|
||||
val a2 = x.w * x.w
|
||||
val n1 = x.x * x.x + x.y * x.y + x.z * x.z
|
||||
val n2 = 4 * x.w * (a2 - n1)
|
||||
return DoubleQuaternion(a2 * a2 - 6 * a2 * n1 + n1 * n1, x.x * n2, x.y * n2, x.z * n2)
|
||||
}
|
||||
|
||||
override fun exp(arg: DoubleQuaternion): DoubleQuaternion {
|
||||
val un = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z
|
||||
if (un == 0.0) return DoubleQuaternion(exp(arg.w))
|
||||
val n1 = sqrt(un)
|
||||
val ea = exp(arg.w)
|
||||
val n2 = ea * sin(n1) / n1
|
||||
return DoubleQuaternion(ea * cos(n1), n2 * arg.x, n2 * arg.y, n2 * arg.z)
|
||||
}
|
||||
|
||||
override fun ln(arg: DoubleQuaternion): DoubleQuaternion {
|
||||
val nu2 = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z
|
||||
|
||||
if (nu2 == 0.0)
|
||||
return if (arg.w > 0)
|
||||
DoubleQuaternion(ln(arg.w), 0, 0, 0)
|
||||
else {
|
||||
val l = ComplexDoubleField { ln(arg.w) }
|
||||
DoubleQuaternion(l.re, l.im, 0, 0)
|
||||
}
|
||||
|
||||
val a = arg.w
|
||||
check(nu2 > 0)
|
||||
val n = sqrt(a * a + nu2)
|
||||
val th = acos(a / n) / sqrt(nu2)
|
||||
return DoubleQuaternion(ln(n), th * arg.x, th * arg.y, th * arg.z)
|
||||
}
|
||||
|
||||
override operator fun Number.plus(b: DoubleQuaternion): DoubleQuaternion =
|
||||
DoubleQuaternion(toDouble() + b.w, b.x, b.y, b.z)
|
||||
|
||||
override operator fun Number.minus(b: DoubleQuaternion): DoubleQuaternion =
|
||||
DoubleQuaternion(toDouble() - b.w, -b.x, -b.y, -b.z)
|
||||
|
||||
override operator fun DoubleQuaternion.plus(b: Number): DoubleQuaternion =
|
||||
DoubleQuaternion(w + b.toDouble(), x, y, z)
|
||||
|
||||
override operator fun DoubleQuaternion.minus(b: Number): DoubleQuaternion =
|
||||
DoubleQuaternion(w - b.toDouble(), x, y, z)
|
||||
|
||||
override operator fun Number.times(b: DoubleQuaternion): DoubleQuaternion =
|
||||
DoubleQuaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z)
|
||||
|
||||
override fun DoubleQuaternion.unaryMinus(): DoubleQuaternion = DoubleQuaternion(-w, -x, -y, -z)
|
||||
override fun norm(arg: DoubleQuaternion): DoubleQuaternion = sqrt(arg.conjugate * arg)
|
||||
|
||||
override fun bindSymbolOrNull(value: String): DoubleQuaternion? = when (value) {
|
||||
"i" -> i
|
||||
"j" -> j
|
||||
"k" -> k
|
||||
else -> null
|
||||
}
|
||||
|
||||
override fun number(value: Number): DoubleQuaternion = DoubleQuaternion(value)
|
||||
|
||||
override fun sinh(arg: DoubleQuaternion): DoubleQuaternion = (exp(arg) - exp(-arg)) / 2.0
|
||||
override fun cosh(arg: DoubleQuaternion): DoubleQuaternion = (exp(arg) + exp(-arg)) / 2.0
|
||||
override fun tanh(arg: DoubleQuaternion): DoubleQuaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg))
|
||||
override fun asinh(arg: DoubleQuaternion): DoubleQuaternion = ln(sqrt(arg * arg + one) + arg)
|
||||
override fun acosh(arg: DoubleQuaternion): DoubleQuaternion = ln(arg + sqrt((arg - one) * (arg + one)))
|
||||
override fun atanh(arg: DoubleQuaternion): DoubleQuaternion = (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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public data class DoubleQuaternion(
|
||||
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<Number>, yz: Complex<Number>) : this(wx.re, wx.im, yz.re, yz.im)
|
||||
public constructor(wx: Complex<Number>) : 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<DoubleQuaternion> {
|
||||
override val objectSize: Int
|
||||
get() = 32
|
||||
|
||||
override fun MemoryReader.read(offset: Int): DoubleQuaternion =
|
||||
DoubleQuaternion(readDouble(offset),
|
||||
readDouble(offset + 8),
|
||||
readDouble(offset + 16),
|
||||
readDouble(offset + 24))
|
||||
|
||||
override fun MemoryWriter.write(offset: Int, value: DoubleQuaternion) {
|
||||
writeDouble(offset, value.w)
|
||||
writeDouble(offset + 8, value.x)
|
||||
writeDouble(offset + 16, value.y)
|
||||
writeDouble(offset + 24, value.z)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the
|
||||
* specified [init] function.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public inline fun Buffer.Companion.quaternion(size: Int, init: (Int) -> DoubleQuaternion): Buffer<DoubleQuaternion> =
|
||||
MemoryBuffer.create(DoubleQuaternion, size, init)
|
||||
|
||||
/**
|
||||
* Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the
|
||||
* specified [init] function.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public inline fun MutableBuffer.Companion.quaternion(
|
||||
size: Int,
|
||||
init: (Int) -> DoubleQuaternion,
|
||||
): MutableBuffer<DoubleQuaternion> =
|
||||
MutableMemoryBuffer.create(DoubleQuaternion, size, init)
|
||||
|
||||
|
@ -1,274 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.memory.MemoryReader
|
||||
import space.kscience.kmath.memory.MemorySpec
|
||||
import space.kscience.kmath.memory.MemoryWriter
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.*
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.MemoryBuffer
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
import space.kscience.kmath.structures.MutableMemoryBuffer
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
* This quaternion's conjugate.
|
||||
*/
|
||||
public val Quaternion.conjugate: Quaternion
|
||||
get() = QuaternionField { z - x * i - y * j - z * k }
|
||||
|
||||
/**
|
||||
* This quaternion's reciprocal.
|
||||
*/
|
||||
public val Quaternion.reciprocal: Quaternion
|
||||
get() {
|
||||
QuaternionField {
|
||||
val n = norm(this@reciprocal)
|
||||
return conjugate / (n * n)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute value of the quaternion.
|
||||
*/
|
||||
public val Quaternion.r: Double
|
||||
get() = sqrt(w * w + x * x + y * y + z * z)
|
||||
|
||||
/**
|
||||
* A field of [Quaternion].
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Quaternion>, PowerOperations<Quaternion>,
|
||||
ExponentialOperations<Quaternion>, NumbersAddOperations<Quaternion>, ScaleOperations<Quaternion> {
|
||||
override val zero: Quaternion = 0.toQuaternion()
|
||||
override val one: Quaternion = 1.toQuaternion()
|
||||
|
||||
/**
|
||||
* The `i` quaternion unit.
|
||||
*/
|
||||
public val i: Quaternion = Quaternion(0, 1)
|
||||
|
||||
/**
|
||||
* The `j` quaternion unit.
|
||||
*/
|
||||
public val j: Quaternion = Quaternion(0, 0, 1)
|
||||
|
||||
/**
|
||||
* The `k` quaternion unit.
|
||||
*/
|
||||
public val k: Quaternion = Quaternion(0, 0, 0, 1)
|
||||
|
||||
override fun add(a: Quaternion, b: Quaternion): Quaternion =
|
||||
Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z)
|
||||
|
||||
override fun scale(a: Quaternion, value: Double): Quaternion =
|
||||
Quaternion(a.w * value, a.x * value, a.y * value, a.z * value)
|
||||
|
||||
override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion(
|
||||
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
|
||||
a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
||||
a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
||||
a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
|
||||
)
|
||||
|
||||
override fun divide(a: Quaternion, b: Quaternion): Quaternion {
|
||||
val s = b.w * b.w + b.x * b.x + b.y * b.y + b.z * b.z
|
||||
|
||||
return Quaternion(
|
||||
(b.w * a.w + b.x * a.x + b.y * a.y + b.z * a.z) / s,
|
||||
(b.w * a.x - b.x * a.w - b.y * a.z + b.z * a.y) / s,
|
||||
(b.w * a.y + b.x * a.z - b.y * a.w - b.z * a.x) / s,
|
||||
(b.w * a.z - b.x * a.y + b.y * a.x - b.z * a.w) / s,
|
||||
)
|
||||
}
|
||||
|
||||
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())
|
||||
return exp(pow * ln(arg))
|
||||
}
|
||||
|
||||
private fun pwr(x: Quaternion, a: Int): Quaternion = when {
|
||||
a < 0 -> -(pwr(x, -a))
|
||||
a == 0 -> one
|
||||
a == 1 -> x
|
||||
a == 2 -> pwr2(x)
|
||||
a == 3 -> pwr3(x)
|
||||
a == 4 -> pwr4(x)
|
||||
|
||||
else -> {
|
||||
val x4 = pwr4(x)
|
||||
var y = x4
|
||||
repeat((1 until a / 4).count()) { y *= x4 }
|
||||
if (a % 4 == 3) y *= pwr3(x)
|
||||
if (a % 4 == 2) y *= pwr2(x)
|
||||
if (a % 4 == 1) y *= x
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
private fun pwr2(x: Quaternion): Quaternion {
|
||||
val aa = 2 * x.w
|
||||
return Quaternion(x.w * x.w - (x.x * x.x + x.y * x.y + x.z * x.z), aa * x.x, aa * x.y, aa * x.z)
|
||||
}
|
||||
|
||||
private fun pwr3(x: Quaternion): Quaternion {
|
||||
val a2 = x.w * x.w
|
||||
val n1 = x.x * x.x + x.y * x.y + x.z * x.z
|
||||
val n2 = 3.0 * a2 - n1
|
||||
return Quaternion(x.w * (a2 - 3 * n1), x.x * n2, x.y * n2, x.z * n2)
|
||||
}
|
||||
|
||||
private fun pwr4(x: Quaternion): Quaternion {
|
||||
val a2 = x.w * x.w
|
||||
val n1 = x.x * x.x + x.y * x.y + x.z * x.z
|
||||
val n2 = 4 * x.w * (a2 - n1)
|
||||
return Quaternion(a2 * a2 - 6 * a2 * n1 + n1 * n1, x.x * n2, x.y * n2, x.z * n2)
|
||||
}
|
||||
|
||||
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()
|
||||
val n1 = sqrt(un)
|
||||
val ea = exp(arg.w)
|
||||
val n2 = ea * sin(n1) / n1
|
||||
return Quaternion(ea * cos(n1), n2 * arg.x, n2 * arg.y, n2 * arg.z)
|
||||
}
|
||||
|
||||
override fun ln(arg: Quaternion): Quaternion {
|
||||
val nu2 = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z
|
||||
|
||||
if (nu2 == 0.0)
|
||||
return if (arg.w > 0)
|
||||
Quaternion(ln(arg.w), 0, 0, 0)
|
||||
else {
|
||||
val l = ComplexField { ln(arg.w.toComplex()) }
|
||||
Quaternion(l.re, l.im, 0, 0)
|
||||
}
|
||||
|
||||
val a = arg.w
|
||||
check(nu2 > 0)
|
||||
val n = sqrt(a * a + nu2)
|
||||
val th = acos(a / n) / sqrt(nu2)
|
||||
return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z)
|
||||
}
|
||||
|
||||
override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z)
|
||||
|
||||
override operator fun Number.minus(b: Quaternion): Quaternion =
|
||||
Quaternion(toDouble() - b.w, -b.x, -b.y, -b.z)
|
||||
|
||||
override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z)
|
||||
override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.toDouble(), x, y, z)
|
||||
|
||||
override operator fun Number.times(b: Quaternion): Quaternion =
|
||||
Quaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z)
|
||||
|
||||
override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z)
|
||||
override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg)
|
||||
|
||||
override fun bindSymbolOrNull(value: String): Quaternion? = when (value) {
|
||||
"i" -> i
|
||||
"j" -> j
|
||||
"k" -> k
|
||||
else -> null
|
||||
}
|
||||
|
||||
override fun number(value: Number): Quaternion = value.toQuaternion()
|
||||
|
||||
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 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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<Quaternion> {
|
||||
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.
|
||||
*/
|
||||
public inline fun Buffer.Companion.quaternion(size: Int, init: (Int) -> Quaternion): Buffer<Quaternion> =
|
||||
MemoryBuffer.create(Quaternion, size, init)
|
||||
|
||||
/**
|
||||
* Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the
|
||||
* specified [init] function.
|
||||
*/
|
||||
public inline fun MutableBuffer.Companion.quaternion(size: Int, init: (Int) -> Quaternion): MutableBuffer<Quaternion> =
|
||||
MutableMemoryBuffer.create(Quaternion, size, init)
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferFactory
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
import space.kscience.kmath.structures.MutableBufferFactory
|
||||
|
||||
|
||||
private class ComplexBuffer<out T : Any>(factory: BufferFactory<T>, override val size: Int, init: (Int) -> Complex<T>) :
|
||||
Buffer<Complex<T>> {
|
||||
private val re: Buffer<T>
|
||||
private val im: Buffer<T>
|
||||
|
||||
init {
|
||||
val tmp = Array(size, init)
|
||||
re = factory(size) { tmp[it].re }
|
||||
im = factory(size) { tmp[it].im }
|
||||
}
|
||||
|
||||
override fun get(index: Int): Complex<T> = Complex(re[index], im[index])
|
||||
|
||||
override fun iterator(): Iterator<Complex<T>> = object : AbstractIterator<Complex<T>>() {
|
||||
private val a = re.iterator()
|
||||
private val b = im.iterator()
|
||||
|
||||
override fun computeNext() = if (a.hasNext() && b.hasNext())
|
||||
setNext(Complex(a.next(), b.next()))
|
||||
else
|
||||
done()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new buffer of complex elements with the specified [size], where each element is calculated by calling the
|
||||
* specified [init] function.
|
||||
*/
|
||||
public fun <T : Any> Buffer.Companion.complex(
|
||||
factory: BufferFactory<T>,
|
||||
size: Int,
|
||||
init: (Int) -> Complex<T>,
|
||||
): Buffer<Complex<T>> = ComplexBuffer(factory, size, init)
|
||||
|
||||
private class MutableComplexBuffer<T : Any> private constructor(
|
||||
override val size: Int,
|
||||
private val re: MutableBuffer<T>,
|
||||
private val im: MutableBuffer<T>,
|
||||
) : MutableBuffer<Complex<T>> {
|
||||
private constructor(
|
||||
factory: MutableBufferFactory<T>,
|
||||
size: Int,
|
||||
tmp: Array<Complex<T>>,
|
||||
) : this(size, factory(size) { tmp[it].re }, factory(size) { tmp[it].im })
|
||||
|
||||
constructor(
|
||||
factory: MutableBufferFactory<T>,
|
||||
size: Int,
|
||||
init: (Int) -> Complex<T>,
|
||||
) : this(factory, size, Array(size, init))
|
||||
|
||||
override fun get(index: Int): Complex<T> = Complex(re[index], im[index])
|
||||
|
||||
override fun set(index: Int, value: Complex<T>) {
|
||||
re[index] = value.re
|
||||
im[index] = value.im
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<Complex<T>> = object : AbstractIterator<Complex<T>>() {
|
||||
private val a = re.iterator()
|
||||
private val b = im.iterator()
|
||||
|
||||
override fun computeNext() = if (a.hasNext() && b.hasNext())
|
||||
setNext(Complex(a.next(), b.next()))
|
||||
else
|
||||
done()
|
||||
}
|
||||
|
||||
override fun copy(): MutableBuffer<Complex<T>> = MutableComplexBuffer(size, re.copy(), im.copy())
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new buffer of complex elements with the specified [size], where each element is calculated by calling the
|
||||
* specified [init] function.
|
||||
*/
|
||||
public fun <T : Any> MutableBuffer.Companion.complex(
|
||||
factory: MutableBufferFactory<T>,
|
||||
size: Int,
|
||||
init: (Int) -> Complex<T>,
|
||||
): MutableBuffer<Complex<T>> = MutableComplexBuffer(factory, size, init)
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.linear.BufferedLinearSpace
|
||||
import space.kscience.kmath.operations.ExtendedField
|
||||
import space.kscience.kmath.operations.NumericAlgebra
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferFactory
|
||||
|
||||
public class ComplexLinearSpace<T : Any, out A>(
|
||||
elementContext: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedLinearSpace<Complex<T>, ComplexRing<T, A>>(
|
||||
ComplexRing(elementContext),
|
||||
{ size, init -> Buffer.complex(bufferFactory, size, init) },
|
||||
) where A : Ring<T>, A : NumericAlgebra<T>
|
||||
|
||||
public fun <T : Any, A> BufferedLinearSpace<T, A>.complex(): ComplexLinearSpace<T, A> where A : ExtendedField<T>, A : NumericAlgebra<T> =
|
||||
ComplexLinearSpace(elementAlgebra, bufferFactory)
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.nd.BufferedExtendedFieldND
|
||||
import space.kscience.kmath.nd.BufferedFieldND
|
||||
import space.kscience.kmath.nd.BufferedGroupND
|
||||
import space.kscience.kmath.nd.BufferedRingND
|
||||
import space.kscience.kmath.operations.*
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferFactory
|
||||
|
||||
public open class ComplexGroupND<T : Any, out A>(
|
||||
shape: IntArray,
|
||||
elementContext: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedGroupND<Complex<T>, ComplexGroup<T, A>>(
|
||||
shape,
|
||||
ComplexGroup(elementContext),
|
||||
{ size, init -> Buffer.complex(bufferFactory, size, init) },
|
||||
) where A : Group<T>, A : NumericAlgebra<T>
|
||||
|
||||
public fun <T : Any, A> BufferedGroupND<T, A>.complex(): ComplexGroupND<T, A> where A : Group<T>, A : NumericAlgebra<T> =
|
||||
ComplexGroupND(shape, elementContext, bufferFactory)
|
||||
|
||||
|
||||
public open class ComplexRingND<T : Any, out A>(
|
||||
shape: IntArray,
|
||||
elementContext: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedRingND<Complex<T>, ComplexRing<T, A>>(
|
||||
shape,
|
||||
ComplexRing(elementContext),
|
||||
{ size, init -> Buffer.complex(bufferFactory, size, init) },
|
||||
) where A : Ring<T>, A : NumericAlgebra<T>
|
||||
|
||||
public fun <T : Any, A> BufferedRingND<T, A>.complex(): ComplexRingND<T, A> where A : Ring<T>, A : NumericAlgebra<T> =
|
||||
ComplexRingND(shape, elementContext, bufferFactory)
|
||||
|
||||
|
||||
public open class ComplexFieldND<T : Any, out A>(
|
||||
shape: IntArray,
|
||||
elementContext: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedFieldND<Complex<T>, ComplexField<T, A>>(
|
||||
shape,
|
||||
ComplexField(elementContext),
|
||||
{ size, init -> Buffer.complex(bufferFactory, size, init) },
|
||||
) where A : Field<T>, A : NumericAlgebra<T>
|
||||
|
||||
public fun <T : Any, A> BufferedFieldND<T, A>.complex(): ComplexFieldND<T, A> where A : Field<T>, A : NumericAlgebra<T> =
|
||||
ComplexFieldND(shape, elementContext, bufferFactory)
|
||||
|
||||
public open class ComplexExtendedFieldND<T : Any, out A>(
|
||||
shape: IntArray,
|
||||
elementContext: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedExtendedFieldND<Complex<T>, ComplexExtendedField<T, A>>(
|
||||
shape,
|
||||
ComplexExtendedField(elementContext),
|
||||
{ size, init -> Buffer.complex(bufferFactory, size, init) },
|
||||
) where A : ExtendedField<T>, A : NumericAlgebra<T>
|
||||
|
||||
public fun <T : Any, A> BufferedExtendedFieldND<T, A>.complex(): ComplexExtendedFieldND<T, A> where A : ExtendedField<T>, A : NumericAlgebra<T> =
|
||||
ComplexExtendedFieldND(shape, elementContext, bufferFactory)
|
@ -6,13 +6,14 @@
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ComplexBufferSpecTest {
|
||||
@Test
|
||||
fun testComplexBuffer() {
|
||||
val buffer = Buffer.complex(20) { Complex(it.toDouble(), -it.toDouble()) }
|
||||
val buffer = Buffer.complex(MutableBuffer.Companion::double, 20) { Complex(it.toDouble(), -it.toDouble()) }
|
||||
assertEquals(Complex(5.0, -5.0), buffer[5])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,11 @@
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.abs
|
||||
import space.kscience.kmath.operations.pi
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
internal class ComplexFieldTest {
|
||||
// TODO make verifier classes available in this source set
|
||||
@ -19,63 +18,84 @@ internal class ComplexFieldTest {
|
||||
|
||||
@Test
|
||||
fun testAddition() {
|
||||
assertEquals(Complex(42, 42), ComplexField { Complex(16, 16) + Complex(26, 26) })
|
||||
assertEquals(Complex(42, 16), ComplexField { Complex(16, 16) + 26 })
|
||||
assertEquals(Complex(42, 16), ComplexField { 26 + Complex(16, 16) })
|
||||
assertEquals(Complex(42, 42), ComplexIntRing { Complex(16, 16) + Complex(26, 26) })
|
||||
assertEquals(Complex(42, 16), ComplexIntRing { Complex(16, 16) + 26 })
|
||||
assertEquals(Complex(42, 16), ComplexIntRing { 26 + Complex(16, 16) })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSubtraction() {
|
||||
assertEquals(Complex(42, 42), ComplexField { Complex(86, 55) - Complex(44, 13) })
|
||||
assertEquals(Complex(42, 56), ComplexField { Complex(86, 56) - 44 })
|
||||
assertEquals(Complex(42, 56), ComplexField { 86 - Complex(44, -56) })
|
||||
assertEquals(Complex(42, 42), ComplexIntRing { Complex(86, 55) - Complex(44, 13) })
|
||||
assertEquals(Complex(42, 56), ComplexIntRing { Complex(86, 56) - 44 })
|
||||
assertEquals(Complex(42, 56), ComplexIntRing { 86 - Complex(44, -56) })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultiplication() {
|
||||
assertEquals(Complex(42, 42), ComplexField { Complex(4.2, 0) * Complex(10, 10) })
|
||||
assertEquals(Complex(42, 21), ComplexField { Complex(4.2, 2.1) * 10 })
|
||||
assertEquals(Complex(42, 21), ComplexField { 10 * Complex(4.2, 2.1) })
|
||||
assertEquals(Complex(42.0, 42.0), ComplexDoubleField { Complex(4.2, 0.0) * Complex(10.0, 10.0) })
|
||||
assertEquals(Complex(42.0, 21.0), ComplexDoubleField { Complex(4.2, 2.1) * 10 })
|
||||
assertEquals(Complex(42.0, 21.0), ComplexDoubleField { 10 * Complex(4.2, 2.1) })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDivision() {
|
||||
assertEquals(Complex(42, 42), ComplexField { Complex(0, 168) / Complex(2, 2) })
|
||||
assertEquals(Complex(42, 56), ComplexField { Complex(86, 56) - 44 })
|
||||
assertEquals(Complex(42, 56), ComplexField { 86 - Complex(44, -56) })
|
||||
assertEquals(Complex(42.0, 42.0), ComplexDoubleField { Complex(0.0, 168.0) / Complex(2.0, 2.0) })
|
||||
assertEquals(Complex(42.0, 56.0), ComplexDoubleField { Complex(86.0, 56.0) - 44.0 })
|
||||
assertEquals(Complex(42.0, 56.0), ComplexDoubleField { 86.0 - Complex(44.0, -56.0) })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSine() {
|
||||
assertEquals(ComplexField { i * sinh(one) }, ComplexField { sin(i) })
|
||||
assertEquals(ComplexField { i * sinh(PI.toComplex()) }, ComplexField { sin(i * PI.toComplex()) })
|
||||
assertEquals(ComplexDoubleField { i * sinh(one) }, ComplexDoubleField { sin(i) })
|
||||
assertEquals(ComplexDoubleField { i * sinh(pi) }, ComplexDoubleField { sin(i * pi) })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInverseSine() {
|
||||
assertEquals(Complex(0, -0.0), ComplexField { asin(zero) })
|
||||
assertTrue(abs(ComplexField { i * asinh(one) }.r - ComplexField { asin(i) }.r) < 0.000000000000001)
|
||||
fun testInverseSine() = ComplexDoubleField {
|
||||
assertEquals(norm(zero), norm(asin(zero)), 1e-10)
|
||||
assertEquals(norm(i * asinh(one)), norm(i * asinh(one)), 1e-10)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInverseHyperbolicSine() {
|
||||
assertEquals(
|
||||
ComplexField { i * PI.toComplex() / 2 },
|
||||
ComplexField { asinh(i) })
|
||||
assertEquals(ComplexDoubleField { i * pi / 2 }, ComplexDoubleField { asinh(i) })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
assertEquals(ComplexField.zero, ComplexField { zero pow 2 })
|
||||
assertEquals(ComplexField.zero, ComplexField { zero pow 2 })
|
||||
assertEquals(ComplexDoubleField.zero, ComplexDoubleField { zero pow 2 })
|
||||
assertEquals(ComplexDoubleField.zero, ComplexDoubleField { zero pow 2 })
|
||||
|
||||
assertEquals(
|
||||
ComplexField { i * 8 }.let { it.im.toInt() to it.re.toInt() },
|
||||
ComplexField { Complex(2, 2) pow 2 }.let { it.im.toInt() to it.re.toInt() })
|
||||
ComplexDoubleField { i * 8 }.let { it.im.toInt() to it.re.toInt() },
|
||||
ComplexDoubleField { Complex(2.0, 2.0) pow 2 }.let { it.im.toInt() to it.re.toInt() },
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNorm() {
|
||||
assertEquals(2.toComplex(), ComplexField { norm(2 * i) })
|
||||
assertEquals(2.0, ComplexDoubleField { norm(number(2.0) * i) })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun conjugate() = ComplexDoubleField {
|
||||
assertEquals(Complex(0.0, 42.0), Complex(0.0, -42.0).conjugate)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reciprocal() = ComplexDoubleField {
|
||||
assertEquals(norm(Complex(0.5, 0.0)), norm(Complex(2.0, 0.0).reciprocal), 1e-10)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun polar() {
|
||||
val num = Complex(0.5, 2.5)
|
||||
val theta = ComplexDoubleField { num.theta }
|
||||
val r = ComplexDoubleField { num.r }
|
||||
|
||||
DoubleField {
|
||||
assertEquals(cos(theta), num.re / r, 1e-10)
|
||||
assertEquals(sin(theta), num.im / r, 1e-10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
internal class ComplexTest {
|
||||
@Test
|
||||
fun conjugate() = ComplexField { assertEquals(Complex(0, 42), Complex(0, -42).conjugate) }
|
||||
|
||||
@Test
|
||||
fun reciprocal() = ComplexField { assertTrue((Complex(0.5, -0.0) - 2.toComplex().reciprocal).r < 1e-10) }
|
||||
|
||||
@Test
|
||||
fun r() = ComplexField { assertEquals(sqrt(2.0), (i + 1.0.toComplex()).r) }
|
||||
|
||||
@Test
|
||||
fun theta() = assertEquals(0.0, 1.toComplex().theta)
|
||||
|
||||
@Test
|
||||
fun toComplex() {
|
||||
assertEquals(Complex(42), 42.toComplex())
|
||||
assertEquals(Complex(42.0), 42.0.toComplex())
|
||||
assertEquals(Complex(42f), 42f.toComplex())
|
||||
assertEquals(Complex(42.0), 42.0.toComplex())
|
||||
assertEquals(Complex(42.toByte()), 42.toByte().toComplex())
|
||||
assertEquals(Complex(42.toShort()), 42.toShort().toComplex())
|
||||
}
|
||||
}
|
@ -17,11 +17,11 @@ internal class ExpressionFieldForComplexTest {
|
||||
|
||||
@Test
|
||||
fun testComplex() {
|
||||
val expression = FunctionalExpressionField(ComplexField).run {
|
||||
val expression = FunctionalExpressionField(ComplexDoubleField).run {
|
||||
val x = bindSymbol(x)
|
||||
x * x + 2 * x + one
|
||||
}
|
||||
|
||||
assertEquals(expression(x to Complex(1.0, 0.0)), Complex(4.0, 0.0))
|
||||
assertEquals(Complex(4.0, 0.0), expression(x to Complex(1.0, 0.0)))
|
||||
}
|
||||
}
|
||||
|
@ -4,47 +4,47 @@
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class QuaternionFieldTest {
|
||||
@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) })
|
||||
}
|
||||
|
||||
//
|
||||
//import space.kscience.kmath.operations.invoke
|
||||
//import kotlin.test.Test
|
||||
//import kotlin.test.assertEquals
|
||||
//
|
||||
//internal class QuaternionFieldTest {
|
||||
// @Test
|
||||
// fun testSubtraction() {
|
||||
// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(86, 55) - Quaternion(44, 13) })
|
||||
// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 })
|
||||
// assertEquals(Quaternion(42, 56), QuaternionField { 86 - Quaternion(44, -56) })
|
||||
// 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) })
|
||||
// }
|
||||
|
||||
@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) })
|
||||
}
|
||||
|
||||
//
|
||||
//// @Test
|
||||
//// fun testSubtraction() {
|
||||
//// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(86, 55) - Quaternion(44, 13) })
|
||||
//// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 })
|
||||
//// assertEquals(Quaternion(42, 56), QuaternionField { 86 - Quaternion(44, -56) })
|
||||
//// }
|
||||
//
|
||||
// @Test
|
||||
// fun testDivision() {
|
||||
// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(0, 168) / Quaternion(2, 2) })
|
||||
// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 })
|
||||
// assertEquals(Quaternion(42, 56) , QuaternionField { 86 - Quaternion(44, -56) })
|
||||
// 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) })
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
|
||||
assertEquals(QuaternionField.zero, QuaternionField { 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() })
|
||||
}
|
||||
}
|
||||
//
|
||||
//// @Test
|
||||
//// fun testDivision() {
|
||||
//// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(0, 168) / Quaternion(2, 2) })
|
||||
//// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 })
|
||||
//// assertEquals(Quaternion(42, 56) , QuaternionField { 86 - Quaternion(44, -56) })
|
||||
//// }
|
||||
//
|
||||
// @Test
|
||||
// fun testPower() {
|
||||
// assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
|
||||
// assertEquals(QuaternionField.zero, QuaternionField { 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() })
|
||||
// }
|
||||
//}
|
||||
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.operations.JBigDecimalField
|
||||
import space.kscience.kmath.operations.JBigIntegerRing
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
|
||||
/**
|
||||
* [ComplexRing] instance for [JBigIntegerRing].
|
||||
*/
|
||||
public val ComplexJBigIntegerRing: ComplexRing<BigInteger, JBigIntegerRing> = ComplexRing(JBigIntegerRing)
|
||||
|
||||
/**
|
||||
* [ComplexRing] instance for [JBigDecimalField].
|
||||
*/
|
||||
public val ComplexJBigDecimalField: ComplexField<BigDecimal, JBigDecimalField.Companion> =
|
||||
ComplexField(JBigDecimalField)
|
@ -15,9 +15,9 @@ import space.kscience.kmath.structures.VirtualBuffer
|
||||
import space.kscience.kmath.structures.indices
|
||||
|
||||
|
||||
public class BufferedLinearSpace<T : Any, out A : Ring<T>>(
|
||||
public open class BufferedLinearSpace<T : Any, out A : Ring<T>>(
|
||||
override val elementAlgebra: A,
|
||||
private val bufferFactory: BufferFactory<T>,
|
||||
public val bufferFactory: BufferFactory<T>,
|
||||
) : LinearSpace<T, A> {
|
||||
|
||||
private fun ndRing(
|
||||
|
@ -286,3 +286,11 @@ public interface FieldND<T, out F : Field<T>> : Field<StructureND<T>>, RingND<T,
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended field of [StructureND].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param F the type of extended field of structure elements.
|
||||
*/
|
||||
public interface ExtendedFieldND<T, out F : ExtendedField<T>> : ExtendedField<StructureND<T>>, FieldND<T, F>
|
||||
|
@ -57,11 +57,11 @@ public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
public open class BufferedGroupND<T, out A : Group<T>>(
|
||||
public open class BufferedGroupND<T, out G : Group<T>>(
|
||||
final override val shape: IntArray,
|
||||
final override val elementContext: A,
|
||||
final override val elementContext: G,
|
||||
final override val bufferFactory: BufferFactory<T>,
|
||||
) : GroupND<T, A>, BufferAlgebraND<T, A> {
|
||||
) : GroupND<T, G>, BufferAlgebraND<T, G> {
|
||||
override val strides: Strides = DefaultStrides(shape)
|
||||
override val zero: BufferND<T> by lazy { produce { zero } }
|
||||
override fun StructureND<T>.unaryMinus(): StructureND<T> = produce { -get(it) }
|
||||
@ -75,15 +75,32 @@ public open class BufferedRingND<T, out R : Ring<T>>(
|
||||
override val one: BufferND<T> by lazy { produce { one } }
|
||||
}
|
||||
|
||||
public open class BufferedFieldND<T, out R : Field<T>>(
|
||||
public open class BufferedFieldND<T, out F : Field<T>>(
|
||||
shape: IntArray,
|
||||
elementContext: R,
|
||||
elementContext: F,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedRingND<T, R>(shape, elementContext, bufferFactory), FieldND<T, R> {
|
||||
) : BufferedRingND<T, F>(shape, elementContext, bufferFactory), FieldND<T, F> {
|
||||
|
||||
override fun scale(a: StructureND<T>, value: Double): StructureND<T> = a.map { it * value }
|
||||
}
|
||||
|
||||
public open class BufferedExtendedFieldND<T, out F : ExtendedField<T>>(
|
||||
shape: IntArray,
|
||||
elementContext: F,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedFieldND<T, F>(shape, elementContext, bufferFactory), ExtendedFieldND<T, F> {
|
||||
public override fun sin(arg: StructureND<T>): StructureND<T> = arg.map { elementContext.sin(it) }
|
||||
public override fun cos(arg: StructureND<T>): StructureND<T> = arg.map { elementContext.cos(it) }
|
||||
public override fun asin(arg: StructureND<T>): StructureND<T> = arg.map { elementContext.asin(it) }
|
||||
public override fun acos(arg: StructureND<T>): StructureND<T> = arg.map { elementContext.acos(it) }
|
||||
public override fun atan(arg: StructureND<T>): StructureND<T> = arg.map { elementContext.atan(it) }
|
||||
public override fun power(arg: StructureND<T>, pow: Number): StructureND<T> =
|
||||
arg.map { elementContext.power(it, pow) }
|
||||
|
||||
public override fun exp(arg: StructureND<T>): StructureND<T> = arg.map { elementContext.exp(it) }
|
||||
public override fun ln(arg: StructureND<T>): StructureND<T> = arg.map { elementContext.ln(it) }
|
||||
}
|
||||
|
||||
// group factories
|
||||
public fun <T, A : Ring<T>> AlgebraND.Companion.group(
|
||||
space: A,
|
||||
@ -139,4 +156,28 @@ public inline fun <T, A : Field<T>, R> A.ndField(
|
||||
): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return AlgebraND.field(this, bufferFactory, *shape).run(action)
|
||||
}
|
||||
}
|
||||
|
||||
public fun <T, A : ExtendedField<T>> AlgebraND.Companion.extendedField(
|
||||
field: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
): BufferedExtendedFieldND<T, A> = BufferedExtendedFieldND(shape, field, bufferFactory)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public inline fun <reified T : Any, A : ExtendedField<T>> AlgebraND.Companion.auto(
|
||||
field: A,
|
||||
vararg shape: Int,
|
||||
): FieldND<T, A> = when (field) {
|
||||
DoubleField -> DoubleFieldND(shape) as FieldND<T, A>
|
||||
else -> BufferedFieldND(shape, field, Buffer.Companion::auto)
|
||||
}
|
||||
|
||||
public inline fun <T, A : ExtendedField<T>, R> A.ndExtendedField(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
action: BufferedExtendedFieldND<T, A>.() -> R,
|
||||
): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return AlgebraND.extendedField(this, bufferFactory, *shape).run(action)
|
||||
}
|
||||
|
@ -7,9 +7,7 @@ package space.kscience.kmath.nd
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.ExtendedField
|
||||
import space.kscience.kmath.operations.NumbersAddOperations
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
@ -17,10 +15,8 @@ import kotlin.contracts.contract
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class DoubleFieldND(
|
||||
shape: IntArray,
|
||||
) : BufferedFieldND<Double, DoubleField>(shape, DoubleField, ::DoubleBuffer),
|
||||
NumbersAddOperations<StructureND<Double>>,
|
||||
ScaleOperations<StructureND<Double>>,
|
||||
ExtendedField<StructureND<Double>> {
|
||||
) : BufferedExtendedFieldND<Double, DoubleField>(shape, DoubleField, ::DoubleBuffer),
|
||||
NumbersAddOperations<StructureND<Double>> {
|
||||
|
||||
override val zero: BufferND<Double> by lazy { produce { zero } }
|
||||
override val one: BufferND<Double> by lazy { produce { one } }
|
||||
@ -103,7 +99,7 @@ public class DoubleFieldND(
|
||||
override fun atanh(arg: StructureND<Double>): BufferND<Double> = arg.map { atanh(it) }
|
||||
}
|
||||
|
||||
public fun AlgebraND.Companion.real(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape)
|
||||
public fun AlgebraND.Companion.double(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape)
|
||||
|
||||
/**
|
||||
* Produce a context for n-dimensional operations inside this real field
|
||||
|
@ -7,7 +7,7 @@ package space.kscience.kmath.structures
|
||||
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.get
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.nd.double
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.testutils.FieldVerifier
|
||||
import kotlin.test.Test
|
||||
@ -16,12 +16,12 @@ import kotlin.test.assertEquals
|
||||
internal class NDFieldTest {
|
||||
@Test
|
||||
fun verify() {
|
||||
(AlgebraND.real(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) }
|
||||
(AlgebraND.double(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testStrides() {
|
||||
val ndArray = AlgebraND.real(10, 10).produce { (it[0] + it[1]).toDouble() }
|
||||
val ndArray = AlgebraND.double(10, 10).produce { (it[0] + it[1]).toDouble() }
|
||||
assertEquals(ndArray[5, 5], 10.0)
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import kotlin.test.assertEquals
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
class NumberNDFieldTest {
|
||||
val algebra = AlgebraND.real(3, 3)
|
||||
val algebra = AlgebraND.double(3, 3)
|
||||
val array1 = algebra.produce { (i, j) -> (i + j).toDouble() }
|
||||
val array2 = algebra.produce { (i, j) -> (i - j).toDouble() }
|
||||
|
||||
@ -83,7 +83,7 @@ class NumberNDFieldTest {
|
||||
@Test
|
||||
fun testInternalContext() {
|
||||
algebra {
|
||||
(AlgebraND.real(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } }
|
||||
(AlgebraND.double(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ import java.math.BigInteger
|
||||
import java.math.MathContext
|
||||
|
||||
/**
|
||||
* A field over [BigInteger].
|
||||
* A ring over [BigInteger].
|
||||
*/
|
||||
public object JBigIntegerField : Ring<BigInteger>, NumericAlgebra<BigInteger> {
|
||||
public object JBigIntegerRing : Ring<BigInteger>, NumericAlgebra<BigInteger> {
|
||||
override val zero: BigInteger get() = BigInteger.ZERO
|
||||
|
||||
override val one: BigInteger get() = BigInteger.ONE
|
@ -28,7 +28,7 @@ public class DoubleHistogramSpace(
|
||||
public val dimension: Int get() = lower.size
|
||||
|
||||
private val shape = IntArray(binNums.size) { binNums[it] + 2 }
|
||||
override val histogramValueSpace: DoubleFieldND = AlgebraND.real(*shape)
|
||||
override val histogramValueSpace: DoubleFieldND = AlgebraND.double(*shape)
|
||||
|
||||
override val strides: Strides get() = histogramValueSpace.strides
|
||||
private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] }
|
||||
|
@ -1,5 +1,6 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.jvm")
|
||||
kotlin("jvm")
|
||||
id("ru.mipt.npm.gradle.common")
|
||||
}
|
||||
|
||||
description = "Jafama integration module"
|
||||
|
@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.jvm")
|
||||
kotlin("jvm")
|
||||
kotlin("jupyter.api")
|
||||
id("ru.mipt.npm.gradle.common")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -9,13 +10,8 @@ dependencies {
|
||||
api(project(":kmath-for-real"))
|
||||
}
|
||||
|
||||
kscience{
|
||||
useHtml()
|
||||
}
|
||||
|
||||
readme {
|
||||
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
|
||||
}
|
||||
kscience.useHtml()
|
||||
readme.maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
|
||||
|
||||
kotlin.sourceSets.all {
|
||||
languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
|
||||
|
@ -17,7 +17,7 @@ import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess
|
||||
import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer
|
||||
import space.kscience.kmath.ast.rendering.renderWithStringBuilder
|
||||
import space.kscience.kmath.complex.Complex
|
||||
import space.kscience.kmath.complex.Quaternion
|
||||
import space.kscience.kmath.complex.DoubleQuaternion
|
||||
import space.kscience.kmath.expressions.MST
|
||||
import space.kscience.kmath.expressions.MstRing
|
||||
import space.kscience.kmath.misc.PerformancePitfall
|
||||
@ -126,18 +126,16 @@ internal class KMathJupyter : JupyterIntegration() {
|
||||
})
|
||||
}
|
||||
|
||||
render<Complex> {
|
||||
MstRing {
|
||||
number(it.re) + number(it.im) * bindSymbol("i")
|
||||
}.toDisplayResult()
|
||||
render<Complex<Number>> {
|
||||
MstRing { number(it.re) + number(it.im) * bindSymbol("i") }.toDisplayResult()
|
||||
}
|
||||
|
||||
render<Quaternion> {
|
||||
render<DoubleQuaternion> {
|
||||
MstRing {
|
||||
number(it.w) +
|
||||
number(it.x) * bindSymbol("i") +
|
||||
number(it.x) * bindSymbol("j") +
|
||||
number(it.x) * bindSymbol("k")
|
||||
number(it.y) * bindSymbol("j") +
|
||||
number(it.z) * bindSymbol("k")
|
||||
}.toDisplayResult()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user