forked from kscience/kmath
Improve support of string-identified operations API, rework trigonometric operations algebra part: introduce inverse trigonometric operations, rename tg to tan
This commit is contained in:
parent
5dc07febe3
commit
2e5c13aea9
@ -59,8 +59,10 @@ class DerivativeStructureField(
|
||||
override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b)
|
||||
|
||||
override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin()
|
||||
|
||||
override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos()
|
||||
override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin()
|
||||
override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos()
|
||||
override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan()
|
||||
|
||||
override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) {
|
||||
is Double -> arg.pow(pow)
|
||||
@ -136,6 +138,3 @@ object DiffExpressionContext : ExpressionContext<Double, DiffExpression>, Field<
|
||||
override fun divide(a: DiffExpression, b: DiffExpression) =
|
||||
DiffExpression { a.function(this) / b.function(this) }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -8,6 +8,8 @@ import scientifik.memory.MemorySpec
|
||||
import scientifik.memory.MemoryWriter
|
||||
import kotlin.math.*
|
||||
|
||||
private val PI_DIV_2 = Complex(PI / 2, 0)
|
||||
|
||||
/**
|
||||
* A field for complex numbers
|
||||
*/
|
||||
@ -30,9 +32,11 @@ object ComplexField : ExtendedFieldOperations<Complex>, Field<Complex> {
|
||||
return Complex((a.re * b.re + a.im * b.im) / norm, (a.re * b.im - a.im * b.re) / norm)
|
||||
}
|
||||
|
||||
override fun sin(arg: Complex): Complex = i / 2 * (exp(-i * arg) - exp(i * arg))
|
||||
|
||||
override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2
|
||||
override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2
|
||||
override fun asin(arg: Complex): Complex = -i * ln(sqrt(one - arg pow 2) + i * arg)
|
||||
override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(one - arg pow 2) + i * arg)
|
||||
override fun atan(arg: Complex): Complex = i * (ln(one - i * arg) - ln(one + i * arg)) / 2
|
||||
|
||||
override fun power(arg: Complex, pow: Number): Complex =
|
||||
arg.r.pow(pow.toDouble()) * (cos(pow.toDouble() * arg.theta) + i * sin(pow.toDouble() * arg.theta))
|
||||
|
@ -8,7 +8,7 @@ import kotlin.math.pow as kpow
|
||||
*/
|
||||
interface ExtendedFieldOperations<T> :
|
||||
FieldOperations<T>,
|
||||
TrigonometricOperations<T>,
|
||||
InverseTrigonometricOperations<T>,
|
||||
PowerOperations<T>,
|
||||
ExponentialOperations<T>
|
||||
|
||||
@ -44,6 +44,10 @@ object RealField : ExtendedField<Double>, Norm<Double, Double> {
|
||||
|
||||
override inline fun sin(arg: Double) = kotlin.math.sin(arg)
|
||||
override inline fun cos(arg: Double) = kotlin.math.cos(arg)
|
||||
override inline fun tan(arg: Double): Double = kotlin.math.tan(arg)
|
||||
override inline fun acos(arg: Double): Double = kotlin.math.acos(arg)
|
||||
override inline fun asin(arg: Double): Double = kotlin.math.asin(arg)
|
||||
override inline fun atan(arg: Double): Double = kotlin.math.atan(arg)
|
||||
|
||||
override inline fun power(arg: Double, pow: Number) = arg.kpow(pow.toDouble())
|
||||
|
||||
@ -75,6 +79,10 @@ object FloatField : ExtendedField<Float>, Norm<Float, Float> {
|
||||
|
||||
override inline fun sin(arg: Float) = kotlin.math.sin(arg)
|
||||
override inline fun cos(arg: Float) = kotlin.math.cos(arg)
|
||||
override inline fun tan(arg: Float) = kotlin.math.tan(arg)
|
||||
override inline fun acos(arg: Float) = kotlin.math.acos(arg)
|
||||
override inline fun asin(arg: Float) = kotlin.math.asin(arg)
|
||||
override inline fun atan(arg: Float) = kotlin.math.atan(arg)
|
||||
|
||||
override inline fun power(arg: Float, pow: Number) = arg.pow(pow.toFloat())
|
||||
|
||||
@ -180,4 +188,4 @@ object LongRing : Ring<Long>, Norm<Long, Long> {
|
||||
override inline fun Long.minus(b: Long) = (this - b)
|
||||
|
||||
override inline fun Long.times(b: Long) = (this * b)
|
||||
}
|
||||
}
|
||||
|
@ -13,16 +13,33 @@ package scientifik.kmath.operations
|
||||
interface TrigonometricOperations<T> : FieldOperations<T> {
|
||||
fun sin(arg: T): T
|
||||
fun cos(arg: T): T
|
||||
fun tan(arg: T): T = sin(arg) / cos(arg)
|
||||
|
||||
fun tg(arg: T): T = sin(arg) / cos(arg)
|
||||
companion object {
|
||||
const val SIN_OPERATION = "sin"
|
||||
const val COS_OPERATION = "cos"
|
||||
const val TAN_OPERATION = "tan"
|
||||
}
|
||||
}
|
||||
|
||||
fun ctg(arg: T): T = cos(arg) / sin(arg)
|
||||
interface InverseTrigonometricOperations<T> : TrigonometricOperations<T> {
|
||||
fun asin(arg: T): T
|
||||
fun acos(arg: T): T
|
||||
fun atan(arg: T): T
|
||||
|
||||
companion object {
|
||||
const val ASIN_OPERATION = "asin"
|
||||
const val ACOS_OPERATION = "acos"
|
||||
const val ATAN_OPERATION = "atan"
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : MathElement<out TrigonometricOperations<T>>> sin(arg: T): T = arg.context.sin(arg)
|
||||
fun <T : MathElement<out TrigonometricOperations<T>>> cos(arg: T): T = arg.context.cos(arg)
|
||||
fun <T : MathElement<out TrigonometricOperations<T>>> tg(arg: T): T = arg.context.tg(arg)
|
||||
fun <T : MathElement<out TrigonometricOperations<T>>> ctg(arg: T): T = arg.context.ctg(arg)
|
||||
fun <T : MathElement<out TrigonometricOperations<T>>> tan(arg: T): T = arg.context.tan(arg)
|
||||
fun <T : MathElement<out InverseTrigonometricOperations<T>>> asin(arg: T): T = arg.context.asin(arg)
|
||||
fun <T : MathElement<out InverseTrigonometricOperations<T>>> acos(arg: T): T = arg.context.acos(arg)
|
||||
fun <T : MathElement<out InverseTrigonometricOperations<T>>> atan(arg: T): T = arg.context.atan(arg)
|
||||
|
||||
/* Power and roots */
|
||||
|
||||
@ -32,8 +49,11 @@ fun <T : MathElement<out TrigonometricOperations<T>>> ctg(arg: T): T = arg.conte
|
||||
interface PowerOperations<T> : Algebra<T> {
|
||||
fun power(arg: T, pow: Number): T
|
||||
fun sqrt(arg: T) = power(arg, 0.5)
|
||||
|
||||
infix fun T.pow(pow: Number) = power(this, pow)
|
||||
|
||||
companion object {
|
||||
const val SQRT_OPERATION = "sqrt"
|
||||
}
|
||||
}
|
||||
|
||||
infix fun <T : MathElement<out PowerOperations<T>>> T.pow(power: Double): T = context.power(this, power)
|
||||
@ -42,7 +62,7 @@ fun <T : MathElement<out PowerOperations<T>>> sqr(arg: T): T = arg pow 2.0
|
||||
|
||||
/* Exponential */
|
||||
|
||||
interface ExponentialOperations<T>: Algebra<T> {
|
||||
interface ExponentialOperations<T> : Algebra<T> {
|
||||
fun exp(arg: T): T
|
||||
fun ln(arg: T): T
|
||||
}
|
||||
@ -54,4 +74,4 @@ interface Norm<in T : Any, out R> {
|
||||
fun norm(arg: T): R
|
||||
}
|
||||
|
||||
fun <T : MathElement<out Norm<T, R>>, R> norm(arg: T): R = arg.context.norm(arg)
|
||||
fun <T : MathElement<out Norm<T, R>>, R> norm(arg: T): R = arg.context.norm(arg)
|
||||
|
@ -79,6 +79,13 @@ class ComplexNDField(override val shape: IntArray) :
|
||||
|
||||
override fun cos(arg: NDBuffer<Complex>) = map(arg) { cos(it) }
|
||||
|
||||
override fun tan(arg: NDBuffer<Complex>): NDBuffer<Complex> = map(arg) { tan(it) }
|
||||
|
||||
override fun asin(arg: NDBuffer<Complex>): NDBuffer<Complex> = map(arg) { asin(it) }
|
||||
|
||||
override fun acos(arg: NDBuffer<Complex>): NDBuffer<Complex> = map(arg) {acos(it)}
|
||||
|
||||
override fun atan(arg: NDBuffer<Complex>): NDBuffer<Complex> = map(arg) {atan(it)}
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@ import scientifik.kmath.operations.*
|
||||
|
||||
interface ExtendedNDField<T : Any, F, N : NDStructure<T>> :
|
||||
NDField<T, F, N>,
|
||||
TrigonometricOperations<N>,
|
||||
InverseTrigonometricOperations<N>,
|
||||
PowerOperations<N>,
|
||||
ExponentialOperations<N>
|
||||
where F : ExtendedFieldOperations<T>, F : Field<T>
|
||||
|
@ -9,8 +9,10 @@ import kotlin.math.*
|
||||
* A simple field over linear buffers of [Double]
|
||||
*/
|
||||
object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
|
||||
|
||||
override fun add(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||
require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " }
|
||||
|
||||
return if (a is DoubleBuffer && b is DoubleBuffer) {
|
||||
val aArray = a.array
|
||||
val bArray = b.array
|
||||
@ -22,6 +24,7 @@ object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
|
||||
|
||||
override fun multiply(a: Buffer<Double>, k: Number): DoubleBuffer {
|
||||
val kValue = k.toDouble()
|
||||
|
||||
return if (a is DoubleBuffer) {
|
||||
val aArray = a.array
|
||||
DoubleBuffer(DoubleArray(a.size) { aArray[it] * kValue })
|
||||
@ -32,6 +35,7 @@ object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
|
||||
|
||||
override fun multiply(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||
require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " }
|
||||
|
||||
return if (a is DoubleBuffer && b is DoubleBuffer) {
|
||||
val aArray = a.array
|
||||
val bArray = b.array
|
||||
@ -43,6 +47,7 @@ object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
|
||||
|
||||
override fun divide(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||
require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " }
|
||||
|
||||
return if (a is DoubleBuffer && b is DoubleBuffer) {
|
||||
val aArray = a.array
|
||||
val bArray = b.array
|
||||
@ -52,49 +57,67 @@ object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun sin(arg: Buffer<Double>): DoubleBuffer {
|
||||
return if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) })
|
||||
}
|
||||
override fun sin(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) })
|
||||
}
|
||||
|
||||
override fun cos(arg: Buffer<Double>): DoubleBuffer {
|
||||
return if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) })
|
||||
}
|
||||
override fun cos(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) })
|
||||
}
|
||||
|
||||
override fun power(arg: Buffer<Double>, pow: Number): DoubleBuffer {
|
||||
return if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) })
|
||||
}
|
||||
override fun tan(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { tan(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { tan(arg[it]) })
|
||||
}
|
||||
|
||||
override fun exp(arg: Buffer<Double>): DoubleBuffer {
|
||||
return if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) })
|
||||
}
|
||||
override fun asin(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { asin(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { asin(arg[it]) })
|
||||
}
|
||||
|
||||
override fun ln(arg: Buffer<Double>): DoubleBuffer {
|
||||
return if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) })
|
||||
}
|
||||
override fun acos(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { acos(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { acos(arg[it]) })
|
||||
}
|
||||
|
||||
override fun atan(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { atan(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { atan(arg[it]) })
|
||||
}
|
||||
|
||||
override fun power(arg: Buffer<Double>, pow: Number): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) })
|
||||
}
|
||||
|
||||
override fun exp(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) })
|
||||
}
|
||||
|
||||
override fun ln(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||
val array = arg.array
|
||||
DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) })
|
||||
} else {
|
||||
DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) })
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +142,6 @@ class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
|
||||
return RealBufferFieldOperations.multiply(a, b)
|
||||
}
|
||||
|
||||
|
||||
override fun divide(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
|
||||
return RealBufferFieldOperations.divide(a, b)
|
||||
@ -135,6 +157,26 @@ class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
|
||||
return RealBufferFieldOperations.cos(arg)
|
||||
}
|
||||
|
||||
override fun tan(arg: Buffer<Double>): DoubleBuffer {
|
||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||
return RealBufferFieldOperations.tan(arg)
|
||||
}
|
||||
|
||||
override fun asin(arg: Buffer<Double>): DoubleBuffer {
|
||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||
return RealBufferFieldOperations.asin(arg)
|
||||
}
|
||||
|
||||
override fun acos(arg: Buffer<Double>): DoubleBuffer {
|
||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||
return RealBufferFieldOperations.acos(arg)
|
||||
}
|
||||
|
||||
override fun atan(arg: Buffer<Double>): DoubleBuffer {
|
||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||
return RealBufferFieldOperations.atan(arg)
|
||||
}
|
||||
|
||||
override fun power(arg: Buffer<Double>, pow: Number): DoubleBuffer {
|
||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||
return RealBufferFieldOperations.power(arg, pow)
|
||||
@ -149,5 +191,4 @@ class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
|
||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||
return RealBufferFieldOperations.ln(arg)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,13 @@ class RealNDField(override val shape: IntArray) :
|
||||
|
||||
override fun cos(arg: NDBuffer<Double>) = map(arg) { cos(it) }
|
||||
|
||||
override fun tan(arg: NDBuffer<Double>): NDBuffer<Double> = map(arg) { tan(it) }
|
||||
|
||||
override fun asin(arg: NDBuffer<Double>): NDBuffer<Double> = map(arg) { asin(it) }
|
||||
|
||||
override fun acos(arg: NDBuffer<Double>): NDBuffer<Double> = map(arg) { acos(it) }
|
||||
|
||||
override fun atan(arg: NDBuffer<Double>): NDBuffer<Double> = map(arg) { atan(it) }
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user