Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved trigonometry operations #114

Merged
merged 24 commits into from
Jun 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2e5c13a
Improve support of string-identified operations API, rework trigonome…
CommanderTvis Jun 9, 2020
62ca19b
Merge remote-tracking branch 'mipt-npm/adv-expr' into adv-expr-improv…
CommanderTvis Jun 11, 2020
757332e
Merge remote-tracking branch 'mipt-npm/dev' into adv-expr-improved-tr…
CommanderTvis Jun 11, 2020
a5fea4f
Merge remote-tracking branch 'mipt-npm/dev' into adv-expr-improved-tr…
CommanderTvis Jun 11, 2020
af9e1bb
Merge remote-tracking branch 'mipt-npm/dev' into adv-expr-improved-tr…
CommanderTvis Jun 12, 2020
76ad027
Merge remote-tracking branch 'mipt-npm/adv-expr' into adv-expr-improv…
CommanderTvis Jun 13, 2020
48b688b
Fix minor problems occured after merge
CommanderTvis Jun 13, 2020
95d5e4a
Merge remote-tracking branch 'mipt-npm/adv-expr' into adv-expr-improv…
CommanderTvis Jun 13, 2020
9b2eab6
Merge remote-tracking branch 'mipt-npm/dev' into adv-expr-improved-tr…
CommanderTvis Jun 13, 2020
1e2460c
Rename
CommanderTvis Jun 15, 2020
c10901a
Merge branch 'adv-expr' into adv-expr-improved-trigonometry
CommanderTvis Jun 15, 2020
f8f1814
Merge remote-tracking branch 'mipt-npm/adv-expr' into adv-expr-improv…
CommanderTvis Jun 16, 2020
8693ddc
Merge remote-tracking branch 'mipt-npm/adv-expr' into adv-expr-improv…
CommanderTvis Jun 16, 2020
d309032
Merge remote-tracking branch 'mipt-npm/dev' into adv-expr-improved-tr…
CommanderTvis Jun 16, 2020
41a81e7
Merge remote-tracking branch 'mipt-npm/adv-expr' into adv-expr-improv…
CommanderTvis Jun 16, 2020
418c296
Merge remote-tracking branch 'mipt-npm/adv-expr' into adv-expr-improv…
CommanderTvis Jun 19, 2020
d7968c0
Merge remote-tracking branch 'mipt-npm/adv-expr' into adv-expr-improv…
CommanderTvis Jun 19, 2020
13e2f96
Merge remote-tracking branch 'space/adv-expr' into adv-expr-improved-…
CommanderTvis Jun 23, 2020
a152f5e
Merge remote-tracking branch 'origin/master' into adv-expr-improved-t…
CommanderTvis Jun 23, 2020
7ddab02
Merge remote-tracking branch 'origin/adv-expr' into adv-expr-improved…
CommanderTvis Jun 24, 2020
e47ec1a
Delete AsmCompiledExpression abstract class, implement dynamic field …
CommanderTvis Jun 25, 2020
a275e74
Add mapping for other dynamic operations
CommanderTvis Jun 26, 2020
a71c02e
Merge remote-tracking branch 'origin/dev' into adv-expr-improved-trig…
CommanderTvis Jun 27, 2020
e91c5a5
Minor refactor for changed ExtendedFieldOperations, replace DoubleBuf…
CommanderTvis Jun 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -136,6 +138,3 @@ object DiffExpressionAlgebra : ExpressionAlgebra<Double, DiffExpression>, Field<
override fun divide(a: DiffExpression, b: DiffExpression) =
DiffExpression { a.function(this) / b.function(this) }
}



Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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)
}

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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import kotlin.math.pow as kpow
* Advanced Number-like field that implements basic operations
*/
interface ExtendedFieldOperations<T> :
FieldOperations<T>,
TrigonometricOperations<T>,
InverseTrigonometricOperations<T>,
PowerOperations<T>,
ExponentialOperations<T> {

Expand All @@ -17,21 +16,21 @@ interface ExtendedFieldOperations<T> :
override fun unaryOperation(operation: String, arg: T): T = when (operation) {
TrigonometricOperations.COS_OPERATION -> cos(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)
ExponentialOperations.EXP_OPERATION -> exp(arg)
ExponentialOperations.LN_OPERATION -> ln(arg)
else -> super.unaryOperation(operation, arg)
}

}

interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T> {
override fun rightSideNumberOperation(operation: String, left: T, right: Number): T {
return when (operation) {
PowerOperations.POW_OPERATION -> power(left, right)
else -> super.rightSideNumberOperation(operation, left, right)
}

override fun rightSideNumberOperation(operation: String, left: T, right: Number): T = when (operation) {
PowerOperations.POW_OPERATION -> power(left, right)
else -> super.rightSideNumberOperation(operation, left, right)
}
}

Expand Down Expand Up @@ -65,7 +64,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) = 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())

Expand Down Expand Up @@ -97,8 +99,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): Float = kotlin.math.tan(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())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,43 @@ package scientifik.kmath.operations
* It also allows to override behavior for optional operations
*
*/
interface TrigonometricOperations<T> {
interface TrigonometricOperations<T> : FieldOperations<T> {
fun sin(arg: T): T
fun cos(arg: T): T

fun tan(arg: T): T

companion object {
const val SIN_OPERATION = "sin"
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>>> 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 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 */

/**
* 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 sqrt(arg: T) = power(arg, 0.5)

Expand All @@ -49,7 +64,7 @@ fun <T : MathElement<out PowerOperations<T>>> sqr(arg: T): T = arg pow 2.0

/* Exponential */

interface ExponentialOperations<T> {
interface ExponentialOperations<T> : Algebra<T> {
fun exp(arg: T): T
fun ln(arg: T): T

Expand All @@ -66,4 +81,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)
Original file line number Diff line number Diff line change
Expand Up @@ -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)}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,97 +11,106 @@ import kotlin.math.*
object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
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} " }

return if (a is RealBuffer && b is RealBuffer) {
val aArray = a.array
val bArray = b.array
RealBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] })
} else {
} else
RealBuffer(DoubleArray(a.size) { a[it] + b[it] })
}
}

override fun multiply(a: Buffer<Double>, k: Number): RealBuffer {
val kValue = k.toDouble()

return if (a is RealBuffer) {
val aArray = a.array
RealBuffer(DoubleArray(a.size) { aArray[it] * kValue })
} else {
} else
RealBuffer(DoubleArray(a.size) { a[it] * kValue })
}
}

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} " }

return if (a is RealBuffer && b is RealBuffer) {
val aArray = a.array
val bArray = b.array
RealBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] })
} else {
} else
RealBuffer(DoubleArray(a.size) { a[it] * b[it] })
}
}

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} " }

return if (a is RealBuffer && b is RealBuffer) {
val aArray = a.array
val bArray = b.array
RealBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] })
} else {
} else
RealBuffer(DoubleArray(a.size) { a[it] / b[it] })
}
}

override fun sin(arg: Buffer<Double>): RealBuffer {
return if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { sin(array[it]) })
} else {
RealBuffer(DoubleArray(arg.size) { sin(arg[it]) })
}
}

override fun cos(arg: Buffer<Double>): RealBuffer {
return if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { cos(array[it]) })
} else {
RealBuffer(DoubleArray(arg.size) { cos(arg[it]) })
}
}

override fun power(arg: Buffer<Double>, pow: Number): RealBuffer {
return if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) })
} else {
RealBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) })
}
}

override fun exp(arg: Buffer<Double>): RealBuffer {
return 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 {
return if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { ln(array[it]) })
} else {
RealBuffer(DoubleArray(arg.size) { ln(arg[it]) })
}
}
override fun sin(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { sin(array[it]) })
} else {
RealBuffer(DoubleArray(arg.size) { sin(arg[it]) })
}

override fun cos(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { cos(array[it]) })
} else
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 acos(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { acos(array[it]) })
} else
RealBuffer(DoubleArray(arg.size) { acos(arg[it]) })

override fun atan(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { atan(array[it]) })
} else
RealBuffer(DoubleArray(arg.size) { atan(arg[it]) })

override fun power(arg: Buffer<Double>, pow: Number): RealBuffer = if (arg is RealBuffer) {
val array = arg.array
RealBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) })
} else
RealBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) })

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>> {

override val zero: Buffer<Double> by lazy { RealBuffer(size) { 0.0 } }

override val one: Buffer<Double> by lazy { RealBuffer(size) { 1.0 } }

override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
Expand All @@ -119,7 +128,6 @@ class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
return RealBufferFieldOperations.multiply(a, b)
}


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" }
return RealBufferFieldOperations.divide(a, b)
Expand All @@ -135,6 +143,26 @@ class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
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 {
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
return RealBufferFieldOperations.power(arg, pow)
Expand All @@ -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" }
return RealBufferFieldOperations.ln(arg)
}

}
}
Loading