Merge pull request #114 from mipt-npm/adv-expr-improved-trigonometry

Improved trigonometry operations
This commit is contained in:
Alexander Nozik 2020-06-27 16:39:37 +03:00 committed by GitHub
commit 896cc3dc51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 147 additions and 74 deletions

View File

@ -0,0 +1,10 @@
package scientifik.kmath.asm.internal
import org.objectweb.asm.Label
import org.objectweb.asm.commons.InstructionAdapter
internal fun InstructionAdapter.label(): Label {
val l = Label()
visitLabel(l)
return l
}

View File

@ -59,8 +59,10 @@ class DerivativeStructureField(
override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b) override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b)
override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin() override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin()
override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos() 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) { override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) {
is Double -> arg.pow(pow) is Double -> arg.pow(pow)
@ -136,6 +138,3 @@ object DiffExpressionAlgebra : ExpressionAlgebra<Double, DiffExpression>, Field<
override fun divide(a: DiffExpression, b: DiffExpression) = override fun divide(a: DiffExpression, b: DiffExpression) =
DiffExpression { a.function(this) / b.function(this) } DiffExpression { a.function(this) / b.function(this) }
} }

View File

@ -8,6 +8,8 @@ import scientifik.memory.MemorySpec
import scientifik.memory.MemoryWriter import scientifik.memory.MemoryWriter
import kotlin.math.* import kotlin.math.*
private val PI_DIV_2 = Complex(PI / 2, 0)
/** /**
* A field for complex numbers * A field for complex numbers
*/ */
@ -30,9 +32,11 @@ object ComplexField : ExtendedField<Complex> {
return Complex((a.re * b.re + a.im * b.im) / norm, (a.re * b.im - a.im * b.re) / norm) 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 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 = override fun power(arg: Complex, pow: Number): Complex =
arg.r.pow(pow.toDouble()) * (cos(pow.toDouble() * arg.theta) + i * sin(pow.toDouble() * arg.theta)) arg.r.pow(pow.toDouble()) * (cos(pow.toDouble() * arg.theta) + i * sin(pow.toDouble() * arg.theta))

View File

@ -7,8 +7,7 @@ import kotlin.math.pow as kpow
* Advanced Number-like field that implements basic operations * Advanced Number-like field that implements basic operations
*/ */
interface ExtendedFieldOperations<T> : interface ExtendedFieldOperations<T> :
FieldOperations<T>, InverseTrigonometricOperations<T>,
TrigonometricOperations<T>,
PowerOperations<T>, PowerOperations<T>,
ExponentialOperations<T> { ExponentialOperations<T> {
@ -17,21 +16,21 @@ interface ExtendedFieldOperations<T> :
override fun unaryOperation(operation: String, arg: T): T = when (operation) { override fun unaryOperation(operation: String, arg: T): T = when (operation) {
TrigonometricOperations.COS_OPERATION -> cos(arg) TrigonometricOperations.COS_OPERATION -> cos(arg)
TrigonometricOperations.SIN_OPERATION -> sin(arg) TrigonometricOperations.SIN_OPERATION -> sin(arg)
TrigonometricOperations.TAN_OPERATION -> tan(arg)
InverseTrigonometricOperations.ACOS_OPERATION -> acos(arg)
InverseTrigonometricOperations.ASIN_OPERATION -> asin(arg)
InverseTrigonometricOperations.ATAN_OPERATION -> atan(arg)
PowerOperations.SQRT_OPERATION -> sqrt(arg) PowerOperations.SQRT_OPERATION -> sqrt(arg)
ExponentialOperations.EXP_OPERATION -> exp(arg) ExponentialOperations.EXP_OPERATION -> exp(arg)
ExponentialOperations.LN_OPERATION -> ln(arg) ExponentialOperations.LN_OPERATION -> ln(arg)
else -> super.unaryOperation(operation, arg) else -> super.unaryOperation(operation, arg)
} }
} }
interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T> { interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T> {
override fun rightSideNumberOperation(operation: String, left: T, right: Number): T { override fun rightSideNumberOperation(operation: String, left: T, right: Number): T = when (operation) {
return when (operation) { PowerOperations.POW_OPERATION -> power(left, right)
PowerOperations.POW_OPERATION -> power(left, right) else -> super.rightSideNumberOperation(operation, left, right)
else -> super.rightSideNumberOperation(operation, left, right)
}
} }
} }
@ -65,7 +64,10 @@ object RealField : ExtendedField<Double>, Norm<Double, Double> {
override inline fun sin(arg: Double) = kotlin.math.sin(arg) override inline fun sin(arg: Double) = kotlin.math.sin(arg)
override inline fun cos(arg: Double) = kotlin.math.cos(arg) override inline fun cos(arg: Double) = kotlin.math.cos(arg)
override inline fun tan(arg: Double) = kotlin.math.tan(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()) override inline fun power(arg: Double, pow: Number) = arg.kpow(pow.toDouble())
@ -97,8 +99,10 @@ object FloatField : ExtendedField<Float>, Norm<Float, Float> {
override inline fun sin(arg: Float) = kotlin.math.sin(arg) override inline fun sin(arg: Float) = kotlin.math.sin(arg)
override inline fun cos(arg: Float) = kotlin.math.cos(arg) override inline fun cos(arg: Float) = kotlin.math.cos(arg)
override inline fun tan(arg: Float) = kotlin.math.tan(arg)
override inline fun tan(arg: Float): 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()) override inline fun power(arg: Float, pow: Number) = arg.pow(pow.toFloat())

View File

@ -10,28 +10,43 @@ package scientifik.kmath.operations
* It also allows to override behavior for optional operations * It also allows to override behavior for optional operations
* *
*/ */
interface TrigonometricOperations<T> { interface TrigonometricOperations<T> : FieldOperations<T> {
fun sin(arg: T): T fun sin(arg: T): T
fun cos(arg: T): T fun cos(arg: T): T
fun tan(arg: T): T fun tan(arg: T): T
companion object { companion object {
const val SIN_OPERATION = "sin" const val SIN_OPERATION = "sin"
const val COS_OPERATION = "cos" const val COS_OPERATION = "cos"
const val TAN_OPERATION = "tan"
}
}
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>>> 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>>> cos(arg: T): T = arg.context.cos(arg)
fun <T : MathElement<out TrigonometricOperations<T>>> tan(arg: T): T = arg.context.tan(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 */ /* Power and roots */
/** /**
* A context extension to include power operations like square roots, etc * A context extension to include power operations like square roots, etc
*/ */
interface PowerOperations<T> { interface PowerOperations<T> : Algebra<T> {
fun power(arg: T, pow: Number): T fun power(arg: T, pow: Number): T
fun sqrt(arg: T) = power(arg, 0.5) fun sqrt(arg: T) = power(arg, 0.5)
@ -49,7 +64,7 @@ fun <T : MathElement<out PowerOperations<T>>> sqr(arg: T): T = arg pow 2.0
/* Exponential */ /* Exponential */
interface ExponentialOperations<T> { interface ExponentialOperations<T> : Algebra<T> {
fun exp(arg: T): T fun exp(arg: T): T
fun ln(arg: T): T fun ln(arg: T): T

View File

@ -79,6 +79,13 @@ class ComplexNDField(override val shape: IntArray) :
override fun cos(arg: NDBuffer<Complex>) = map(arg) { cos(it) } 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)}
} }

View File

@ -11,97 +11,106 @@ import kotlin.math.*
object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> { object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer { override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } 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 RealBuffer && b is RealBuffer) { return if (a is RealBuffer && b is RealBuffer) {
val aArray = a.array val aArray = a.array
val bArray = b.array val bArray = b.array
RealBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] }) RealBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] })
} else { } else
RealBuffer(DoubleArray(a.size) { a[it] + b[it] }) RealBuffer(DoubleArray(a.size) { a[it] + b[it] })
}
} }
override fun multiply(a: Buffer<Double>, k: Number): RealBuffer { override fun multiply(a: Buffer<Double>, k: Number): RealBuffer {
val kValue = k.toDouble() val kValue = k.toDouble()
return if (a is RealBuffer) { return if (a is RealBuffer) {
val aArray = a.array val aArray = a.array
RealBuffer(DoubleArray(a.size) { aArray[it] * kValue }) RealBuffer(DoubleArray(a.size) { aArray[it] * kValue })
} else { } else
RealBuffer(DoubleArray(a.size) { a[it] * kValue }) RealBuffer(DoubleArray(a.size) { a[it] * kValue })
}
} }
override fun multiply(a: Buffer<Double>, b: Buffer<Double>): RealBuffer { override fun multiply(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } 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 RealBuffer && b is RealBuffer) { return if (a is RealBuffer && b is RealBuffer) {
val aArray = a.array val aArray = a.array
val bArray = b.array val bArray = b.array
RealBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] }) RealBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] })
} else { } else
RealBuffer(DoubleArray(a.size) { a[it] * b[it] }) RealBuffer(DoubleArray(a.size) { a[it] * b[it] })
}
} }
override fun divide(a: Buffer<Double>, b: Buffer<Double>): RealBuffer { override fun divide(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } 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 RealBuffer && b is RealBuffer) { return if (a is RealBuffer && b is RealBuffer) {
val aArray = a.array val aArray = a.array
val bArray = b.array val bArray = b.array
RealBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] }) RealBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] })
} else { } else
RealBuffer(DoubleArray(a.size) { a[it] / b[it] }) RealBuffer(DoubleArray(a.size) { a[it] / b[it] })
}
} }
override fun sin(arg: Buffer<Double>): RealBuffer { override fun sin(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
return if (arg is RealBuffer) { val array = arg.array
val array = arg.array RealBuffer(DoubleArray(arg.size) { sin(array[it]) })
RealBuffer(DoubleArray(arg.size) { sin(array[it]) }) } else {
} else { RealBuffer(DoubleArray(arg.size) { sin(arg[it]) })
RealBuffer(DoubleArray(arg.size) { sin(arg[it]) })
}
} }
override fun cos(arg: Buffer<Double>): RealBuffer { override fun cos(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
return if (arg is RealBuffer) { val array = arg.array
val array = arg.array RealBuffer(DoubleArray(arg.size) { cos(array[it]) })
RealBuffer(DoubleArray(arg.size) { cos(array[it]) }) } else
} else { RealBuffer(DoubleArray(arg.size) { cos(arg[it]) })
RealBuffer(DoubleArray(arg.size) { cos(arg[it]) })
} override fun tan(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { tan(array[it]) })
} else
RealBuffer(DoubleArray(arg.size) { tan(arg[it]) })
override fun asin(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { asin(array[it]) })
} else {
RealBuffer(DoubleArray(arg.size) { asin(arg[it]) })
} }
override fun power(arg: Buffer<Double>, pow: Number): RealBuffer { override fun acos(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
return if (arg is RealBuffer) { val array = arg.array
val array = arg.array RealBuffer(DoubleArray(arg.size) { acos(array[it]) })
RealBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) }) } else
} else { RealBuffer(DoubleArray(arg.size) { acos(arg[it]) })
RealBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) })
}
}
override fun exp(arg: Buffer<Double>): RealBuffer { override fun atan(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
return if (arg is RealBuffer) { val array = arg.array
val array = arg.array RealBuffer(DoubleArray(arg.size) { atan(array[it]) })
RealBuffer(DoubleArray(arg.size) { exp(array[it]) }) } else
} else { RealBuffer(DoubleArray(arg.size) { atan(arg[it]) })
RealBuffer(DoubleArray(arg.size) { exp(arg[it]) })
}
}
override fun ln(arg: Buffer<Double>): RealBuffer { override fun power(arg: Buffer<Double>, pow: Number): RealBuffer = if (arg is RealBuffer) {
return if (arg is RealBuffer) { val array = arg.array
val array = arg.array RealBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) })
RealBuffer(DoubleArray(arg.size) { ln(array[it]) }) } else
} else { RealBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) })
RealBuffer(DoubleArray(arg.size) { ln(arg[it]) })
} override fun exp(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
} val array = arg.array
RealBuffer(DoubleArray(arg.size) { exp(array[it]) })
} else
RealBuffer(DoubleArray(arg.size) { exp(arg[it]) })
override fun ln(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { ln(array[it]) })
} else
RealBuffer(DoubleArray(arg.size) { ln(arg[it]) })
} }
class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> { class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
override val zero: Buffer<Double> by lazy { RealBuffer(size) { 0.0 } } override val zero: Buffer<Double> by lazy { RealBuffer(size) { 0.0 } }
override val one: Buffer<Double> by lazy { RealBuffer(size) { 1.0 } } override val one: Buffer<Double> by lazy { RealBuffer(size) { 1.0 } }
override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer { override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
@ -119,7 +128,6 @@ class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
return RealBufferFieldOperations.multiply(a, b) return RealBufferFieldOperations.multiply(a, b)
} }
override fun divide(a: Buffer<Double>, b: Buffer<Double>): RealBuffer { override fun divide(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
return RealBufferFieldOperations.divide(a, b) return RealBufferFieldOperations.divide(a, b)
@ -135,6 +143,26 @@ class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
return RealBufferFieldOperations.cos(arg) return RealBufferFieldOperations.cos(arg)
} }
override fun tan(arg: Buffer<Double>): RealBuffer {
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>): RealBuffer {
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>): RealBuffer {
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>): RealBuffer {
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): RealBuffer { override fun power(arg: Buffer<Double>, pow: Number): RealBuffer {
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
return RealBufferFieldOperations.power(arg, pow) return RealBufferFieldOperations.power(arg, pow)
@ -149,5 +177,4 @@ class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
return RealBufferFieldOperations.ln(arg) return RealBufferFieldOperations.ln(arg)
} }
} }

View File

@ -74,6 +74,13 @@ class RealNDField(override val shape: IntArray) :
override fun cos(arg: NDBuffer<Double>) = map(arg) { cos(it) } 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) }
} }