diff --git a/doc/linear.md b/doc/linear.md index e69de29bb..6208deaff 100644 --- a/doc/linear.md +++ b/doc/linear.md @@ -0,0 +1 @@ +**TODO** \ No newline at end of file diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index 509809a15..305761c01 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -6,6 +6,7 @@ description = "Commons math binding for kmath" dependencies { api(project(":kmath-core")) + api(project(":kmath-sequential")) api("org.apache.commons:commons-math3:3.6.1") testImplementation("org.jetbrains.kotlin:kotlin-test") testImplementation("org.jetbrains.kotlin:kotlin-test-junit") diff --git a/kmath-commons/src/main/kotlin/scientifik/kmath/transform/Transformations.kt b/kmath-commons/src/main/kotlin/scientifik/kmath/transform/Transformations.kt new file mode 100644 index 000000000..a4db4b1bd --- /dev/null +++ b/kmath-commons/src/main/kotlin/scientifik/kmath/transform/Transformations.kt @@ -0,0 +1,63 @@ +package scientifik.kmath.transform + +import org.apache.commons.math3.transform.* +import scientifik.kmath.operations.Complex +import scientifik.kmath.structures.* + + +/** + * + */ +object Transformations { + + private fun Buffer.toArray(): Array = + Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) } + + private fun Buffer.asArray() = if (this is DoubleBuffer) { + array + } else { + DoubleArray(size) { i -> get(i) } + } + + /** + * Create a virtual buffer on top of array + */ + private fun Array.asBuffer() = VirtualBuffer(size) { + val value = get(it) + Complex(value.real, value.imaginary) + } + + fun fourier( + normalization: DftNormalization = DftNormalization.STANDARD, + direction: TransformType = TransformType.FORWARD + ): BufferTransform = { + FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer() + } + + fun realFourier( + normalization: DftNormalization = DftNormalization.STANDARD, + direction: TransformType = TransformType.FORWARD + ): BufferTransform = { + FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer() + } + + fun sine( + normalization: DstNormalization = DstNormalization.STANDARD_DST_I, + direction: TransformType = TransformType.FORWARD + ): BufferTransform = { + FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer() + } + + fun cosine( + normalization: DctNormalization = DctNormalization.STANDARD_DCT_I, + direction: TransformType = TransformType.FORWARD + ): BufferTransform = { + FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer() + } + + fun hadamard( + direction: TransformType = TransformType.FORWARD + ): BufferTransform = { + FastHadamardTransformer().transform(it.asArray(), direction).asBuffer() + } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt index 225c00c82..a89729bae 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt @@ -154,7 +154,7 @@ inline class DoubleBuffer(val array: DoubleArray) : MutableBuffer { array[index] = value } - override fun iterator(): Iterator = array.iterator() + override fun iterator() = array.iterator() override fun copy(): MutableBuffer = DoubleBuffer(array.copyOf()) } @@ -162,7 +162,6 @@ inline class DoubleBuffer(val array: DoubleArray) : MutableBuffer { @Suppress("FunctionName") inline fun DoubleBuffer(size: Int, init: (Int) -> Double) = DoubleBuffer(DoubleArray(size) { init(it) }) - /** * Transform buffer of doubles into array for high performance operations */ @@ -184,7 +183,7 @@ inline class ShortBuffer(val array: ShortArray) : MutableBuffer { array[index] = value } - override fun iterator(): Iterator = array.iterator() + override fun iterator() = array.iterator() override fun copy(): MutableBuffer = ShortBuffer(array.copyOf()) @@ -201,7 +200,7 @@ inline class IntBuffer(val array: IntArray) : MutableBuffer { array[index] = value } - override fun iterator(): Iterator = array.iterator() + override fun iterator() = array.iterator() override fun copy(): MutableBuffer = IntBuffer(array.copyOf()) @@ -218,7 +217,7 @@ inline class LongBuffer(val array: LongArray) : MutableBuffer { array[index] = value } - override fun iterator(): Iterator = array.iterator() + override fun iterator() = array.iterator() override fun copy(): MutableBuffer = LongBuffer(array.copyOf()) @@ -231,7 +230,7 @@ inline class ReadOnlyBuffer(val buffer: MutableBuffer) : Buffer { override fun get(index: Int): T = buffer.get(index) - override fun iterator(): Iterator = buffer.iterator() + override fun iterator() = buffer.iterator() } /** @@ -260,3 +259,8 @@ fun Buffer.asReadOnly(): Buffer = if (this is MutableBuffer) { } else { this } + +/** + * Typealias for buffer transformations + */ +typealias BufferTransform = (Buffer) -> Buffer \ No newline at end of file diff --git a/kmath-sequential/src/commonMain/kotlin/scientifik/kmath/sequential/DoubleProcessors.kt b/kmath-sequential/src/commonMain/kotlin/scientifik/kmath/sequential/DoubleProcessors.kt new file mode 100644 index 000000000..bdeb2d319 --- /dev/null +++ b/kmath-sequential/src/commonMain/kotlin/scientifik/kmath/sequential/DoubleProcessors.kt @@ -0,0 +1,7 @@ +package scientifik.kmath.sequential + +import kotlinx.coroutines.CoroutineScope + +//class FFTProcessor(scope: CoroutineScope): AbstractDoubleProcessor(scope){ +// +//} \ No newline at end of file diff --git a/kmath-sequential/src/commonMain/kotlin/scientifik/kmath/sequential/DoubleStreaming.kt b/kmath-sequential/src/commonMain/kotlin/scientifik/kmath/sequential/DoubleStreaming.kt index d18c76634..c2f048c34 100644 --- a/kmath-sequential/src/commonMain/kotlin/scientifik/kmath/sequential/DoubleStreaming.kt +++ b/kmath-sequential/src/commonMain/kotlin/scientifik/kmath/sequential/DoubleStreaming.kt @@ -7,13 +7,22 @@ import kotlinx.coroutines.channels.* import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.asBuffer +import scientifik.kmath.structures.asSequence + +fun Buffer.asChannel(scope: CoroutineScope): ReceiveChannel = scope.produce { + for (i in (0 until size)) { + send(get(i)) + } +} interface DoubleProducer : Producer { - suspend fun receiveArray(): DoubleArray + suspend fun receiveArray(): Buffer } interface DoubleConsumer : Consumer { - suspend fun sendArray(array: DoubleArray) + suspend fun sendArray(array: Buffer) } abstract class AbstractDoubleProducer(scope: CoroutineScope) : AbstractProducer(scope), DoubleProducer { @@ -79,15 +88,15 @@ abstract class AbstractDoubleProcessor(scope: CoroutineScope) : AbstractProcesso class BasicDoubleProducer( scope: CoroutineScope, capacity: Int = Channel.UNLIMITED, - block: suspend ProducerScope.() -> Unit + block: suspend ProducerScope>.() -> Unit ) : AbstractDoubleProducer(scope) { private val currentArray = atomic?>(null) - private val channel: ReceiveChannel by lazy { produce(capacity = capacity, block = block) } + private val channel: ReceiveChannel> by lazy { produce(capacity = capacity, block = block) } private val cachingChannel by lazy { channel.map { - it.also { doubles -> currentArray.lazySet(doubles.asChannel()) } + it.also { doubles -> currentArray.lazySet(doubles.asChannel(this)) } } } @@ -97,40 +106,39 @@ class BasicDoubleProducer( } } - override suspend fun receiveArray(): DoubleArray = cachingChannel.receive() + override suspend fun receiveArray(): Buffer = cachingChannel.receive() - override suspend fun receive(): Double = (currentArray.value ?: cachingChannel.receive().asChannel()).receive() + override suspend fun receive(): Double = (currentArray.value ?: cachingChannel.receive().asChannel(this)).receive() } class DoubleReducer( scope: CoroutineScope, initialState: S, - val fold: suspend (S, DoubleArray) -> S + val fold: suspend (S, Buffer) -> S ) : AbstractDoubleConsumer(scope) { var state: S = initialState private set - private val mutex = Mutex() - - override suspend fun sendArray(array: DoubleArray) { + override suspend fun sendArray(array: Buffer) { state = fold(state, array) } - override suspend fun send(value: Double) = sendArray(doubleArrayOf(value)) + override suspend fun send(value: Double) = sendArray(doubleArrayOf(value).asBuffer()) } /** * Convert an array to single element producer, splitting it in chunks if necessary */ -fun DoubleArray.produce(scope: CoroutineScope = GlobalScope, chunkSize: Int = Int.MAX_VALUE) = if (size < chunkSize) { - BasicDoubleProducer(scope) { send(this@produce) } -} else { - BasicDoubleProducer(scope) { - //TODO optimize this! - asSequence().chunked(chunkSize).forEach { - send(it.toDoubleArray()) +fun Buffer.produce(scope: CoroutineScope = GlobalScope, chunkSize: Int = Int.MAX_VALUE) = + if (size < chunkSize) { + BasicDoubleProducer(scope) { send(this@produce) } + } else { + BasicDoubleProducer(scope) { + //TODO optimize this! + asSequence().chunked(chunkSize).forEach { + send(it.asBuffer()) + } } - } -} \ No newline at end of file + } \ No newline at end of file