From 3ba12f49993d03e9af6bd59b97186e72e78799f6 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 9 Jul 2021 14:11:26 +0300 Subject: [PATCH] Generic Buffer Algebra --- CHANGELOG.md | 1 + .../kscience/kmath/structures/buffers.kt | 22 +++ .../kmath/operations/BufferAlgebra.kt | 146 ++++++++++++++++++ .../kmath/structures/DoubleBufferField.kt | 4 + 4 files changed, 173 insertions(+) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index e35153d81..8c4f5b547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ - Use `Symbol` factory function instead of `StringSymbol` ### Deprecated +- Specialized `DoubleBufferAlgebra` ### Removed - Nearest in Domain. To be implemented in geometry package. diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt new file mode 100644 index 000000000..eabb16701 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt @@ -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/LICENSE.txt file. + */ + +package space.kscience.kmath.structures + +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.bufferAlgebra +import space.kscience.kmath.operations.produce + +inline fun MutableBuffer.Companion.same( + n: Int, + value: R +): MutableBuffer = auto(n) { value } + + +fun main() { + with(DoubleField.bufferAlgebra(5)) { + println(number(2.0) + produce(1, 2, 3, 4, 5)) + } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt new file mode 100644 index 000000000..9f4d741fd --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -0,0 +1,146 @@ +/* + * 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/LICENSE.txt file. + */ + +package space.kscience.kmath.operations + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferFactory +import space.kscience.kmath.structures.DoubleBuffer + +/** + * An algebra over [Buffer] + */ +@UnstableKMathAPI +public interface BufferAlgebra> : Algebra> { + public val bufferFactory: BufferFactory + public val elementAlgebra: A + + //TODO move to multi-receiver inline extension + public fun Buffer.map(block: (T) -> T): Buffer = bufferFactory(size) { block(get(it)) } + + public fun Buffer.zip(other: Buffer, block: (left: T, right: T) -> T): Buffer { + require(size == other.size) { "Incompatible buffer sizes. left: $size, right: ${other.size}" } + return bufferFactory(size) { block(this[it], other[it]) } + } + + override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { + val operationFunction = elementAlgebra.unaryOperationFunction(operation) + return { arg -> bufferFactory(arg.size) { operationFunction(arg[it]) } } + } + + override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { + val operationFunction = elementAlgebra.binaryOperationFunction(operation) + return { left, right -> + bufferFactory(left.size) { operationFunction(left[it], right[it]) } + } + } +} + +@UnstableKMathAPI +public fun > BufferAlgebra.sin(arg: Buffer): Buffer = + arg.map(elementAlgebra::sin) + +@UnstableKMathAPI +public fun > BufferAlgebra.cos(arg: Buffer): Buffer = + arg.map(elementAlgebra::cos) + +@UnstableKMathAPI +public fun > BufferAlgebra.tan(arg: Buffer): Buffer = + arg.map(elementAlgebra::tan) + +@UnstableKMathAPI +public fun > BufferAlgebra.asin(arg: Buffer): Buffer = + arg.map(elementAlgebra::asin) + +@UnstableKMathAPI +public fun > BufferAlgebra.acos(arg: Buffer): Buffer = + arg.map(elementAlgebra::acos) + +@UnstableKMathAPI +public fun > BufferAlgebra.atan(arg: Buffer): Buffer = + arg.map(elementAlgebra::atan) + +@UnstableKMathAPI +public fun > BufferAlgebra.exp(arg: Buffer): Buffer = + arg.map(elementAlgebra::exp) + +@UnstableKMathAPI +public fun > BufferAlgebra.ln(arg: Buffer): Buffer = + arg.map(elementAlgebra::ln) + +@UnstableKMathAPI +public fun > BufferAlgebra.sinh(arg: Buffer): Buffer = + arg.map(elementAlgebra::sinh) + +@UnstableKMathAPI +public fun > BufferAlgebra.cosh(arg: Buffer): Buffer = + arg.map(elementAlgebra::cosh) + +@UnstableKMathAPI +public fun > BufferAlgebra.tanh(arg: Buffer): Buffer = + arg.map(elementAlgebra::tanh) + +@UnstableKMathAPI +public fun > BufferAlgebra.asinh(arg: Buffer): Buffer = + arg.map(elementAlgebra::asinh) + +@UnstableKMathAPI +public fun > BufferAlgebra.acosh(arg: Buffer): Buffer = + arg.map(elementAlgebra::acosh) + +@UnstableKMathAPI +public fun > BufferAlgebra.atanh(arg: Buffer): Buffer = + arg.map(elementAlgebra::atanh) + +@UnstableKMathAPI +public fun > BufferAlgebra.pow(arg: Buffer, pow: Number): Buffer = + with(elementAlgebra) { arg.map { power(it, pow) } } + + +@UnstableKMathAPI +public class BufferField>( + override val bufferFactory: BufferFactory, + override val elementAlgebra: A, + public val size: Int +) : BufferAlgebra, Field> { + + public fun produce(vararg elements: T): Buffer { + require(elements.size == size) { "Expected $size elements but found ${elements.size}" } + return bufferFactory(size) { elements[it] } + } + + override val zero: Buffer = bufferFactory(size) { elementAlgebra.zero } + override val one: Buffer = bufferFactory(size) { elementAlgebra.one } + + + override fun add(a: Buffer, b: Buffer): Buffer = a.zip(b, elementAlgebra::add) + override fun multiply(a: Buffer, b: Buffer): Buffer = a.zip(b, elementAlgebra::multiply) + override fun divide(a: Buffer, b: Buffer): Buffer = a.zip(b, elementAlgebra::divide) + + override fun scale(a: Buffer, value: Double): Buffer = with(elementAlgebra) { a.map { scale(it, value) } } + override fun Buffer.unaryMinus(): Buffer = with(elementAlgebra) { map { -it } } + + override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { + return super.unaryOperationFunction(operation) + } + + override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { + return super.binaryOperationFunction(operation) + } +} + +//Double buffer specialization + +@UnstableKMathAPI +public fun BufferField.produce(vararg elements: Number): Buffer { + require(elements.size == size) { "Expected $size elements but found ${elements.size}" } + return bufferFactory(size) { elements[it].toDouble() } +} + +@UnstableKMathAPI +public fun DoubleField.bufferAlgebra(size: Int): BufferField = + BufferField(::DoubleBuffer, DoubleField, size) + diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt index e438995dd..c65a0a48a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt @@ -6,6 +6,8 @@ package space.kscience.kmath.structures import space.kscience.kmath.linear.Point +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.ExtendedFieldOperations import space.kscience.kmath.operations.Norm @@ -14,6 +16,7 @@ import kotlin.math.* /** * [ExtendedFieldOperations] over [DoubleBuffer]. */ +@Deprecated("To be replaced by generic BufferAlgebra") public object DoubleBufferFieldOperations : ExtendedFieldOperations> { override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { DoubleBuffer(size) { -array[it] } @@ -172,6 +175,7 @@ public object DoubleL2Norm : Norm, Double> { * * @property size the size of buffers to operate on. */ +@Deprecated("To be replaced by generic BufferAlgebra") public class DoubleBufferField(public val size: Int) : ExtendedField>, Norm, Double> { public override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } public override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } }