From 6c4741ede6558f53e5b90e35f934ba0a83ceb13a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 20 Oct 2021 16:06:45 +0300 Subject: [PATCH 1/9] [WIP] TensorFlow --- kmath-tensorflow/build.gradle.kts | 14 ++ .../kmath/tensorflow/TensorFlowAlgebra.kt | 220 ++++++++++++++++++ settings.gradle.kts | 1 + 3 files changed, 235 insertions(+) create mode 100644 kmath-tensorflow/build.gradle.kts create mode 100644 kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt diff --git a/kmath-tensorflow/build.gradle.kts b/kmath-tensorflow/build.gradle.kts new file mode 100644 index 000000000..fa77a272a --- /dev/null +++ b/kmath-tensorflow/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("ru.mipt.npm.gradle.jvm") +} + +description = "Google tensorflow connector" + +dependencies { + api(project(":kmath-tensors")) + api("org.tensorflow:tensorflow-core-api:0.3.3") +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE +} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt new file mode 100644 index 000000000..849a2e909 --- /dev/null +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -0,0 +1,220 @@ +package space.kscience.kmath.tensorflow + + +import org.tensorflow.Graph +import org.tensorflow.Operand +import org.tensorflow.Output +import org.tensorflow.Session +import org.tensorflow.ndarray.NdArray +import org.tensorflow.op.Ops +import org.tensorflow.op.core.Constant +import org.tensorflow.types.family.TType +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.nd.Shape +import space.kscience.kmath.tensors.api.Tensor +import space.kscience.kmath.tensors.api.TensorAlgebra + +private fun IntArray.toLongArray() = LongArray(size) { get(it).toLong() } +private fun LongArray.toIntArray() = IntArray(size) { get(it).toInt() } + +private val NdArray.scalar: T + get() = getObject() + + +public sealed interface TensorFlowTensor : Tensor + +@JvmInline +public value class TensorFlowArray(public val tensor: NdArray) : Tensor { + override val shape: Shape get() = tensor.shape().asArray().toIntArray() + + override fun get(index: IntArray): T = tensor.getObject(*index.toLongArray()) + + @PerformancePitfall + override fun elements(): Sequence> = sequence { + tensor.scalars().forEachIndexed { index: LongArray, ndArray: NdArray -> + //yield(index.toIntArray() to ndArray.scalar) + TODO() + } + } + + override fun set(index: IntArray, value: T) { + tensor.setObject(value, *index.toLongArray()) + } +} + +public abstract class TensorFlowOutput( + private val graph: Graph, + output: Output +) : TensorFlowTensor { + + public var output: Output = output + internal set + + override val shape: Shape get() = output.shape().asArray().toIntArray() + + protected abstract fun org.tensorflow.Tensor.actualizeTensor(): NdArray + + private val actualTensor by lazy { + val session = Session(graph) + TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor()) + } + + override fun get(index: IntArray): T = actualTensor[index] + + @PerformancePitfall + override fun elements(): Sequence> = actualTensor.elements() + + override fun set(index: IntArray, value: T) { + actualTensor[index] = value + } + +} + + +public abstract class TensorFlowAlgebra internal constructor( + private val graph: Graph +) : TensorAlgebra { + + private val ops by lazy { Ops.create(graph) } + + protected fun Tensor.asTensorFlow(): TensorFlowOutput = if (this is TensorFlowOutput) this else { + TODO() + } + + protected abstract fun Output.wrap(): TensorFlowOutput + + protected abstract fun const(value: T): Constant + + override fun Tensor.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) + get(Shape(0)) else null + + private inline fun Tensor.biOp( + other: Tensor, + operation: (left: Operand, right: Operand) -> Operand + ): TensorFlowOutput { + val left = asTensorFlow().output + val right = other.asTensorFlow().output + return operation(left, right).asOutput().wrap() + } + + private inline fun T.biOp( + other: Tensor, + operation: (left: Operand, right: Operand) -> Operand + ): TensorFlowOutput { + val left = const(this) + val right = other.asTensorFlow().output + return operation(left, right).asOutput().wrap() + } + + private inline fun Tensor.biOp( + value: T, + operation: (left: Operand, right: Operand) -> Operand + ): TensorFlowOutput { + val left = asTensorFlow().output + val right = const(value) + return operation(left, right).asOutput().wrap() + } + + private inline fun Tensor.inPlaceOp( + other: Tensor, + operation: (left: Operand, right: Operand) -> Operand + ): Unit { + val origin = asTensorFlow() + val left = origin.output + val right = other.asTensorFlow().output + origin.output = operation(left, right).asOutput() + } + + private inline fun Tensor.inPlaceOp( + value: T, + operation: (left: Operand, right: Operand) -> Operand + ): Unit { + val origin = asTensorFlow() + val left = origin.output + val right = const(value) + origin.output = operation(left, right).asOutput() + } + + private inline fun unOp(value: Tensor, operation: (Operand) -> Operand): TensorFlowOutput = + operation(value.asTensorFlow().output).asOutput().wrap() + + override fun T.plus(other: Tensor) = biOp(other, ops.math::add) + + override fun Tensor.plus(value: T) = biOp(value, ops.math::add) + + override fun Tensor.plus(other: Tensor) = biOp(other, ops.math::add) + + override fun Tensor.plusAssign(value: T): Unit = inPlaceOp(value, ops.math::add) + + override fun Tensor.plusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::add) + + override fun Tensor.minus(value: T) = biOp(value, ops.math::sub) + + override fun Tensor.minus(other: Tensor) = biOp(other, ops.math::sub) + + override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) + + override fun Tensor.minusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::sub) + + override fun T.times(other: Tensor) = biOp(other, ops.math::mul) + + override fun Tensor.times(value: T) = biOp(value, ops.math::mul) + + override fun Tensor.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) + + override fun Tensor.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul) + + override fun Tensor.timesAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::mul) + + override fun Tensor.unaryMinus() = unOp(this, ops.math::neg) + + override fun Tensor.get(i: Int): Tensor{ + ops. + } + + override fun Tensor.transpose(i: Int, j: Int): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.view(shape: IntArray): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.viewAs(other: Tensor): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.dot(other: Tensor) = biOp(other, ops.math.) + + override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): Tensor = ops.run { + TODO("Not yet implemented") + } + + override fun Tensor.sum(): T { + TODO("Not yet implemented") + } + + override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.min(): T { + TODO("Not yet implemented") + } + + override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.max(): T { + TODO("Not yet implemented") + } + + override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } + + override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index e73381bf2..a29f33824 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,6 +33,7 @@ include( ":kmath-commons", ":kmath-viktor", ":kmath-multik", + ":kmath-tensorflow", ":kmath-optimization", ":kmath-stat", ":kmath-nd4j", -- 2.34.1 From cc114041c4eb2c71248d8a54876d57668286cc95 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 24 Oct 2021 18:33:39 +0300 Subject: [PATCH 2/9] Initial implementation of TensorFlow connector --- .../tensorflow/DoubleTensorFlowAlgebra.kt | 40 +++++++++++++++ .../kmath/tensorflow/TensorFlowAlgebra.kt | 49 +++++++++---------- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 14 +++--- 3 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt new file mode 100644 index 000000000..864205e17 --- /dev/null +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -0,0 +1,40 @@ +package space.kscience.kmath.tensorflow + +import org.tensorflow.Graph +import org.tensorflow.Output +import org.tensorflow.ndarray.NdArray +import org.tensorflow.ndarray.Shape +import org.tensorflow.op.core.Constant +import org.tensorflow.types.TFloat64 +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.tensors.api.Tensor + +public class DoubleTensorFlowOutput( + graph: Graph, + output: Output +) : TensorFlowOutput(graph, output) { + override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = output.asTensor() +} + +public class DoubleTensorFlowAlgebra internal constructor( + graph: Graph +) : TensorFlowAlgebra(graph) { + + override fun Tensor.asTensorFlow(): TensorFlowOutput = + if (this is TensorFlowOutput && output.type() == TFloat64::class.java) { + @Suppress("UNCHECKED_CAST") + this as TensorFlowOutput + } else { + val res = TFloat64.tensorOf(Shape.of(*shape.toLongArray())) { array -> + @OptIn(PerformancePitfall::class) + elements().forEach { (index, value) -> + array.setDouble(value, *index.toLongArray()) + } + } + DoubleTensorFlowOutput(graph, ops.constant(res).asOutput()) + } + + override fun Output.wrap(): TensorFlowOutput = DoubleTensorFlowOutput(graph, this) + + override fun const(value: Double): Constant = ops.constant(value) +} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index 849a2e909..12c1211db 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -14,11 +14,10 @@ import space.kscience.kmath.nd.Shape import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra -private fun IntArray.toLongArray() = LongArray(size) { get(it).toLong() } -private fun LongArray.toIntArray() = IntArray(size) { get(it).toInt() } +internal fun IntArray.toLongArray() = LongArray(size) { get(it).toLong() } +internal fun LongArray.toIntArray() = IntArray(size) { get(it).toInt() } -private val NdArray.scalar: T - get() = getObject() +internal val NdArray.scalar: T get() = getObject() public sealed interface TensorFlowTensor : Tensor @@ -72,14 +71,12 @@ public abstract class TensorFlowOutput( public abstract class TensorFlowAlgebra internal constructor( - private val graph: Graph + protected val graph: Graph ) : TensorAlgebra { - private val ops by lazy { Ops.create(graph) } + protected val ops: Ops by lazy { Ops.create(graph) } - protected fun Tensor.asTensorFlow(): TensorFlowOutput = if (this is TensorFlowOutput) this else { - TODO() - } + protected abstract fun Tensor.asTensorFlow(): TensorFlowOutput protected abstract fun Output.wrap(): TensorFlowOutput @@ -138,27 +135,29 @@ public abstract class TensorFlowAlgebra internal constructor( private inline fun unOp(value: Tensor, operation: (Operand) -> Operand): TensorFlowOutput = operation(value.asTensorFlow().output).asOutput().wrap() - override fun T.plus(other: Tensor) = biOp(other, ops.math::add) + override fun T.plus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::add) - override fun Tensor.plus(value: T) = biOp(value, ops.math::add) + override fun Tensor.plus(value: T): TensorFlowOutput = biOp(value, ops.math::add) - override fun Tensor.plus(other: Tensor) = biOp(other, ops.math::add) + override fun Tensor.plus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::add) override fun Tensor.plusAssign(value: T): Unit = inPlaceOp(value, ops.math::add) override fun Tensor.plusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::add) - override fun Tensor.minus(value: T) = biOp(value, ops.math::sub) + override fun Tensor.minus(value: T): TensorFlowOutput = biOp(value, ops.math::sub) - override fun Tensor.minus(other: Tensor) = biOp(other, ops.math::sub) + override fun Tensor.minus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::sub) + + override fun T.minus(other: Tensor): Tensor = biOp(other, ops.math::sub) override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) override fun Tensor.minusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::sub) - override fun T.times(other: Tensor) = biOp(other, ops.math::mul) + override fun T.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) - override fun Tensor.times(value: T) = biOp(value, ops.math::mul) + override fun Tensor.times(value: T): TensorFlowOutput = biOp(value, ops.math::mul) override fun Tensor.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) @@ -166,14 +165,14 @@ public abstract class TensorFlowAlgebra internal constructor( override fun Tensor.timesAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::mul) - override fun Tensor.unaryMinus() = unOp(this, ops.math::neg) + override fun Tensor.unaryMinus(): TensorFlowOutput = unOp(this, ops.math::neg) - override fun Tensor.get(i: Int): Tensor{ - ops. + override fun Tensor.get(i: Int): Tensor { + TODO("Not yet implemented") } - override fun Tensor.transpose(i: Int, j: Int): Tensor { - TODO("Not yet implemented") + override fun Tensor.transpose(i: Int, j: Int): Tensor = unOp(this) { + ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) } override fun Tensor.view(shape: IntArray): Tensor { @@ -184,15 +183,15 @@ public abstract class TensorFlowAlgebra internal constructor( TODO("Not yet implemented") } - override fun Tensor.dot(other: Tensor) = biOp(other, ops.math.) + override fun Tensor.dot(other: Tensor): TensorFlowOutput = biOp(other) { l, r -> + ops.linalg.matMul(l, r) + } override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): Tensor = ops.run { TODO("Not yet implemented") } - override fun Tensor.sum(): T { - TODO("Not yet implemented") - } + override fun Tensor.sum(): T = TODO("Not yet implemented") override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 16ed4b834..3267e4adb 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -22,7 +22,7 @@ import kotlin.math.* public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra, AnalyticTensorAlgebra, - LinearOpsTensorAlgebra{ + LinearOpsTensorAlgebra { public companion object : DoubleTensorAlgebra() @@ -361,16 +361,16 @@ public open class DoubleTensorAlgebra : dotHelper(a.as2D(), b.as2D(), res.as2D(), l, m1, n) } - if (penultimateDim) { - return resTensor.view( + return if (penultimateDim) { + resTensor.view( resTensor.shape.dropLast(2).toIntArray() + intArrayOf(resTensor.shape.last()) ) + } else if (lastDim) { + resTensor.view(resTensor.shape.dropLast(1).toIntArray()) + } else { + resTensor } - if (lastDim) { - return resTensor.view(resTensor.shape.dropLast(1).toIntArray()) - } - return resTensor } override fun diagonalEmbedding( -- 2.34.1 From 64629561afed6465ef74bc8f51b892c94d17adac Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 28 Oct 2021 10:52:40 +0300 Subject: [PATCH 3/9] [WIP] TensorFlow refactoring --- .../tensorflow/DoubleTensorFlowAlgebra.kt | 26 +++++-- .../kmath/tensorflow/TensorFlowAlgebra.kt | 78 +++++++++---------- 2 files changed, 58 insertions(+), 46 deletions(-) diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt index 864205e17..44420cd76 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -3,11 +3,13 @@ package space.kscience.kmath.tensorflow import org.tensorflow.Graph import org.tensorflow.Output import org.tensorflow.ndarray.NdArray -import org.tensorflow.ndarray.Shape import org.tensorflow.op.core.Constant import org.tensorflow.types.TFloat64 import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.tensors.api.Tensor +import space.kscience.kmath.nd.DefaultStrides +import space.kscience.kmath.nd.Shape +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.DoubleField public class DoubleTensorFlowOutput( graph: Graph, @@ -18,14 +20,28 @@ public class DoubleTensorFlowOutput( public class DoubleTensorFlowAlgebra internal constructor( graph: Graph -) : TensorFlowAlgebra(graph) { +) : TensorFlowAlgebra(graph) { - override fun Tensor.asTensorFlow(): TensorFlowOutput = + override val elementAlgebra: DoubleField get() = DoubleField + + override fun structureND( + shape: Shape, + initializer: DoubleField.(IntArray) -> Double + ): StructureND { + val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> + DefaultStrides(shape).forEach { index -> + array.setDouble(elementAlgebra.initializer(index), *index.toLongArray()) + } + } + return DoubleTensorFlowOutput(graph, ops.constant(res).asOutput()) + } + + override fun StructureND.asTensorFlow(): TensorFlowOutput = if (this is TensorFlowOutput && output.type() == TFloat64::class.java) { @Suppress("UNCHECKED_CAST") this as TensorFlowOutput } else { - val res = TFloat64.tensorOf(Shape.of(*shape.toLongArray())) { array -> + val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> @OptIn(PerformancePitfall::class) elements().forEach { (index, value) -> array.setDouble(value, *index.toLongArray()) diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index 12c1211db..e73620d01 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -11,6 +11,8 @@ import org.tensorflow.op.core.Constant import org.tensorflow.types.family.TType import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.Shape +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.Ring import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra @@ -28,13 +30,7 @@ public value class TensorFlowArray(public val tensor: NdArray) : Tensor override fun get(index: IntArray): T = tensor.getObject(*index.toLongArray()) - @PerformancePitfall - override fun elements(): Sequence> = sequence { - tensor.scalars().forEachIndexed { index: LongArray, ndArray: NdArray -> - //yield(index.toIntArray() to ndArray.scalar) - TODO() - } - } + //TODO implement native element sequence override fun set(index: IntArray, value: T) { tensor.setObject(value, *index.toLongArray()) @@ -70,23 +66,23 @@ public abstract class TensorFlowOutput( } -public abstract class TensorFlowAlgebra internal constructor( +public abstract class TensorFlowAlgebra> internal constructor( protected val graph: Graph -) : TensorAlgebra { +) : TensorAlgebra { protected val ops: Ops by lazy { Ops.create(graph) } - protected abstract fun Tensor.asTensorFlow(): TensorFlowOutput + protected abstract fun StructureND.asTensorFlow(): TensorFlowOutput protected abstract fun Output.wrap(): TensorFlowOutput protected abstract fun const(value: T): Constant - override fun Tensor.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) + override fun StructureND.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) get(Shape(0)) else null - private inline fun Tensor.biOp( - other: Tensor, + private inline fun StructureND.biOp( + other: StructureND, operation: (left: Operand, right: Operand) -> Operand ): TensorFlowOutput { val left = asTensorFlow().output @@ -95,7 +91,7 @@ public abstract class TensorFlowAlgebra internal constructor( } private inline fun T.biOp( - other: Tensor, + other: StructureND, operation: (left: Operand, right: Operand) -> Operand ): TensorFlowOutput { val left = const(this) @@ -103,7 +99,7 @@ public abstract class TensorFlowAlgebra internal constructor( return operation(left, right).asOutput().wrap() } - private inline fun Tensor.biOp( + private inline fun StructureND.biOp( value: T, operation: (left: Operand, right: Operand) -> Operand ): TensorFlowOutput { @@ -113,7 +109,7 @@ public abstract class TensorFlowAlgebra internal constructor( } private inline fun Tensor.inPlaceOp( - other: Tensor, + other: StructureND, operation: (left: Operand, right: Operand) -> Operand ): Unit { val origin = asTensorFlow() @@ -132,46 +128,46 @@ public abstract class TensorFlowAlgebra internal constructor( origin.output = operation(left, right).asOutput() } - private inline fun unOp(value: Tensor, operation: (Operand) -> Operand): TensorFlowOutput = + private inline fun unOp(value: StructureND, operation: (Operand) -> Operand): TensorFlowOutput = operation(value.asTensorFlow().output).asOutput().wrap() - override fun T.plus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::add) + override fun T.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) - override fun Tensor.plus(value: T): TensorFlowOutput = biOp(value, ops.math::add) + override fun StructureND.plus(arg: T): TensorFlowOutput = biOp(arg, ops.math::add) - override fun Tensor.plus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::add) + override fun StructureND.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) override fun Tensor.plusAssign(value: T): Unit = inPlaceOp(value, ops.math::add) - override fun Tensor.plusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::add) + override fun Tensor.plusAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::add) - override fun Tensor.minus(value: T): TensorFlowOutput = biOp(value, ops.math::sub) + override fun StructureND.minus(arg: T): TensorFlowOutput = biOp(arg, ops.math::sub) - override fun Tensor.minus(other: Tensor): TensorFlowOutput = biOp(other, ops.math::sub) + override fun StructureND.minus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::sub) - override fun T.minus(other: Tensor): Tensor = biOp(other, ops.math::sub) + override fun T.minus(arg: StructureND): Tensor = biOp(arg, ops.math::sub) override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) - override fun Tensor.minusAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::sub) + override fun Tensor.minusAssign(other: StructureND): Unit = inPlaceOp(other, ops.math::sub) - override fun T.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) + override fun T.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) - override fun Tensor.times(value: T): TensorFlowOutput = biOp(value, ops.math::mul) + override fun StructureND.times(arg: T): TensorFlowOutput = biOp(arg, ops.math::mul) - override fun Tensor.times(other: Tensor): TensorFlowOutput = biOp(other, ops.math::mul) + override fun StructureND.times(other: StructureND): TensorFlowOutput = biOp(other, ops.math::mul) override fun Tensor.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul) - override fun Tensor.timesAssign(other: Tensor): Unit = inPlaceOp(other, ops.math::mul) + override fun Tensor.timesAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::mul) - override fun Tensor.unaryMinus(): TensorFlowOutput = unOp(this, ops.math::neg) + override fun StructureND.unaryMinus(): TensorFlowOutput = unOp(this, ops.math::neg) - override fun Tensor.get(i: Int): Tensor { + override fun StructureND.get(i: Int): Tensor { TODO("Not yet implemented") } - override fun Tensor.transpose(i: Int, j: Int): Tensor = unOp(this) { + override fun StructureND.transpose(i: Int, j: Int): Tensor = unOp(this) { ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) } @@ -179,11 +175,11 @@ public abstract class TensorFlowAlgebra internal constructor( TODO("Not yet implemented") } - override fun Tensor.viewAs(other: Tensor): Tensor { + override fun Tensor.viewAs(other: StructureND): Tensor { TODO("Not yet implemented") } - override fun Tensor.dot(other: Tensor): TensorFlowOutput = biOp(other) { l, r -> + override fun StructureND.dot(other: StructureND): TensorFlowOutput = biOp(other) { l, r -> ops.linalg.matMul(l, r) } @@ -191,29 +187,29 @@ public abstract class TensorFlowAlgebra internal constructor( TODO("Not yet implemented") } - override fun Tensor.sum(): T = TODO("Not yet implemented") + override fun StructureND.sum(): T = TODO("Not yet implemented") - override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor { + override fun StructureND.sum(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } - override fun Tensor.min(): T { + override fun StructureND.min(): T { TODO("Not yet implemented") } - override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor { + override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } - override fun Tensor.max(): T { + override fun StructureND.max(): T { TODO("Not yet implemented") } - override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor { + override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } - override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor { + override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { TODO("Not yet implemented") } } \ No newline at end of file -- 2.34.1 From db06d10cc28a12bf7529375939878c53cdeb96c2 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 28 Oct 2021 19:25:10 +0100 Subject: [PATCH 4/9] dot fixed for tensorflow --- .../space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt | 4 +++- .../kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index e73620d01..90485a9ad 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -180,7 +180,9 @@ public abstract class TensorFlowAlgebra> internal cons } override fun StructureND.dot(other: StructureND): TensorFlowOutput = biOp(other) { l, r -> - ops.linalg.matMul(l, r) + ops.linalg.matMul( + if (l.asTensor().shape().numDimensions() == 1) ops.expandDims(l,ops.constant(0)) else l, + if (r.asTensor().shape().numDimensions() == 1) ops.expandDims(r,ops.constant(-1)) else r) } override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): Tensor = ops.run { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 8c445cf2d..672e37b98 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -208,7 +208,7 @@ public interface TensorAlgebra> : RingOpsND { * * 3. If the first argument is 1-dimensional and the second argument is 2-dimensional, * a 1 is prepended to its dimension for the purpose of the matrix multiply. - * After the matrix multiply, the prepended dimension is removed. + * After the matrix multiply, depending on the implementation the prepended dimension might be removed. * * 4. If the first argument is 2-dimensional and the second argument is 1-dimensional, * the matrix-vector product is returned. -- 2.34.1 From 6c2abdaab03de31084ece8b53f4e53c4c0e5c17a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 10 Nov 2021 20:04:29 +0300 Subject: [PATCH 5/9] First tensorflow test. --- kmath-tensorflow/build.gradle.kts | 1 + .../tensorflow/DoubleTensorFlowAlgebra.kt | 27 ++++- .../kmath/tensorflow/IntTensorFlowAlgebra.kt | 21 ++++ .../kmath/tensorflow/TensorFlowAlgebra.kt | 104 ++++++++++-------- .../kmath/tensorflow/DoubleTensorFlowOps.kt | 19 ++++ .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 2 + 6 files changed, 127 insertions(+), 47 deletions(-) create mode 100644 kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt create mode 100644 kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt diff --git a/kmath-tensorflow/build.gradle.kts b/kmath-tensorflow/build.gradle.kts index fa77a272a..c8307f01f 100644 --- a/kmath-tensorflow/build.gradle.kts +++ b/kmath-tensorflow/build.gradle.kts @@ -7,6 +7,7 @@ description = "Google tensorflow connector" dependencies { api(project(":kmath-tensors")) api("org.tensorflow:tensorflow-core-api:0.3.3") + testImplementation("org.tensorflow:tensorflow-core-platform:0.3.3") } readme { diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt index 44420cd76..eb8245944 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -5,6 +5,7 @@ import org.tensorflow.Output import org.tensorflow.ndarray.NdArray import org.tensorflow.op.core.Constant import org.tensorflow.types.TFloat64 +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.Shape @@ -13,20 +14,22 @@ import space.kscience.kmath.operations.DoubleField public class DoubleTensorFlowOutput( graph: Graph, - output: Output + output: Output, ) : TensorFlowOutput(graph, output) { - override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = output.asTensor() + + override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TFloat64 + } public class DoubleTensorFlowAlgebra internal constructor( - graph: Graph + graph: Graph, ) : TensorFlowAlgebra(graph) { override val elementAlgebra: DoubleField get() = DoubleField override fun structureND( shape: Shape, - initializer: DoubleField.(IntArray) -> Double + initializer: DoubleField.(IntArray) -> Double, ): StructureND { val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> DefaultStrides(shape).forEach { index -> @@ -53,4 +56,20 @@ public class DoubleTensorFlowAlgebra internal constructor( override fun Output.wrap(): TensorFlowOutput = DoubleTensorFlowOutput(graph, this) override fun const(value: Double): Constant = ops.constant(value) + + +} + +public fun DoubleField.produceWithTF( + block: DoubleTensorFlowAlgebra.() -> StructureND, +): StructureND = Graph().use { graph -> + val scope = DoubleTensorFlowAlgebra(graph) + scope.export(scope.block()) +} + +public fun DoubleField.produceMapWithTF( + block: DoubleTensorFlowAlgebra.() -> Map>, +): Map> = Graph().use { graph -> + val scope = DoubleTensorFlowAlgebra(graph) + scope.block().mapValues { scope.export(it.value) } } \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt new file mode 100644 index 000000000..084a445e0 --- /dev/null +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt @@ -0,0 +1,21 @@ +package space.kscience.kmath.tensorflow + +import org.tensorflow.Graph +import org.tensorflow.Output +import org.tensorflow.ndarray.NdArray +import org.tensorflow.types.TInt32 +import org.tensorflow.types.TInt64 + +public class IntTensorFlowOutput( + graph: Graph, + output: Output, +) : TensorFlowOutput(graph, output) { + override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TInt32 +} + +public class LongTensorFlowOutput( + graph: Graph, + output: Output, +) : TensorFlowOutput(graph, output) { + override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TInt64 +} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index e73620d01..1f978c0fc 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -8,8 +8,13 @@ import org.tensorflow.Session import org.tensorflow.ndarray.NdArray import org.tensorflow.op.Ops import org.tensorflow.op.core.Constant +import org.tensorflow.op.core.Max +import org.tensorflow.op.core.Min +import org.tensorflow.op.core.Sum +import org.tensorflow.types.TInt32 import org.tensorflow.types.family.TType import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Ring @@ -38,8 +43,8 @@ public value class TensorFlowArray(public val tensor: NdArray) : Tensor } public abstract class TensorFlowOutput( - private val graph: Graph, - output: Output + protected val graph: Graph, + output: Output, ) : TensorFlowTensor { public var output: Output = output @@ -49,9 +54,10 @@ public abstract class TensorFlowOutput( protected abstract fun org.tensorflow.Tensor.actualizeTensor(): NdArray - private val actualTensor by lazy { - val session = Session(graph) - TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor()) + internal val actualTensor by lazy { + Session(graph).use { session -> + TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor()) + } } override fun get(index: IntArray): T = actualTensor[index] @@ -66,9 +72,9 @@ public abstract class TensorFlowOutput( } -public abstract class TensorFlowAlgebra> internal constructor( - protected val graph: Graph -) : TensorAlgebra { +public abstract class TensorFlowAlgebra> internal constructor( + protected val graph: Graph, +) : TensorAlgebra { protected val ops: Ops by lazy { Ops.create(graph) } @@ -83,7 +89,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun StructureND.biOp( other: StructureND, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { val left = asTensorFlow().output val right = other.asTensorFlow().output @@ -92,7 +98,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun T.biOp( other: StructureND, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { val left = const(this) val right = other.asTensorFlow().output @@ -101,7 +107,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun StructureND.biOp( value: T, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { val left = asTensorFlow().output val right = const(value) @@ -110,7 +116,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun Tensor.inPlaceOp( other: StructureND, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): Unit { val origin = asTensorFlow() val left = origin.output @@ -120,7 +126,7 @@ public abstract class TensorFlowAlgebra> internal cons private inline fun Tensor.inPlaceOp( value: T, - operation: (left: Operand, right: Operand) -> Operand + operation: (left: Operand, right: Operand) -> Operand, ): Unit { val origin = asTensorFlow() val left = origin.output @@ -128,8 +134,8 @@ public abstract class TensorFlowAlgebra> internal cons origin.output = operation(left, right).asOutput() } - private inline fun unOp(value: StructureND, operation: (Operand) -> Operand): TensorFlowOutput = - operation(value.asTensorFlow().output).asOutput().wrap() + private inline fun StructureND.unOp(operation: (Operand) -> Operand): TensorFlowOutput = + operation(asTensorFlow().output).asOutput().wrap() override fun T.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) @@ -149,67 +155,79 @@ public abstract class TensorFlowAlgebra> internal cons override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) - override fun Tensor.minusAssign(other: StructureND): Unit = inPlaceOp(other, ops.math::sub) + override fun Tensor.minusAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::sub) override fun T.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) override fun StructureND.times(arg: T): TensorFlowOutput = biOp(arg, ops.math::mul) - override fun StructureND.times(other: StructureND): TensorFlowOutput = biOp(other, ops.math::mul) + override fun StructureND.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) override fun Tensor.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul) override fun Tensor.timesAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::mul) - override fun StructureND.unaryMinus(): TensorFlowOutput = unOp(this, ops.math::neg) + override fun StructureND.unaryMinus(): TensorFlowOutput = unOp(ops.math::neg) - override fun StructureND.get(i: Int): Tensor { + override fun Tensor.get(i: Int): Tensor = unOp { TODO("Not yet implemented") } - override fun StructureND.transpose(i: Int, j: Int): Tensor = unOp(this) { + override fun Tensor.transpose(i: Int, j: Int): Tensor = unOp { ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) } - override fun Tensor.view(shape: IntArray): Tensor { - TODO("Not yet implemented") + override fun Tensor.view(shape: IntArray): Tensor = unOp { + ops.reshape(it, ops.constant(shape)) } - override fun Tensor.viewAs(other: StructureND): Tensor { - TODO("Not yet implemented") + override fun Tensor.viewAs(other: StructureND): Tensor = biOp(other) { l, r -> + ops.reshape(l, ops.shape(r)) } override fun StructureND.dot(other: StructureND): TensorFlowOutput = biOp(other) { l, r -> ops.linalg.matMul(l, r) } - override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): Tensor = ops.run { - TODO("Not yet implemented") + override fun diagonalEmbedding( + diagonalEntries: Tensor, + offset: Int, + dim1: Int, + dim2: Int, + ): TensorFlowOutput = diagonalEntries.unOp { + TODO() } - override fun StructureND.sum(): T = TODO("Not yet implemented") + override fun StructureND.sum(): T = unOp { + ops.sum(it, ops.constant(intArrayOf())) + }.value() - override fun StructureND.sum(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") + override fun StructureND.sum(dim: Int, keepDim: Boolean): TensorFlowOutput = unOp { + ops.sum(it, ops.constant(dim), Sum.keepDims(keepDim)) } - override fun StructureND.min(): T { - TODO("Not yet implemented") + override fun StructureND.min(): T = unOp { + ops.min(it, ops.constant(intArrayOf())) + }.value() + + override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor = unOp { + ops.min(it, ops.constant(dim), Min.keepDims(keepDim)) } - override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") + override fun StructureND.max(): T = unOp { + ops.max(it, ops.constant(intArrayOf())) + }.value() + + override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor = unOp { + ops.max(it, ops.constant(dim), Max.keepDims(keepDim)) } - override fun StructureND.max(): T { - TODO("Not yet implemented") - } + override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor = IntTensorFlowOutput( + graph, + ops.math.argMax(asTensorFlow().output, ops.constant(dim), TInt32::class.java).output() + ).actualTensor - override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") - } + @OptIn(UnstableKMathAPI::class) + override fun export(arg: StructureND): StructureND = + if (arg is TensorFlowOutput) arg.actualTensor else arg } \ No newline at end of file diff --git a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt new file mode 100644 index 000000000..b7a4b94b4 --- /dev/null +++ b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt @@ -0,0 +1,19 @@ +package space.kscience.kmath.tensorflow + +import org.junit.jupiter.api.Test +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.structureND +import space.kscience.kmath.operations.DoubleField + +class DoubleTensorFlowOps { + @Test + fun basicOps() { + val res = DoubleField.produceWithTF { + val initial = structureND(2, 2) { 1.0 } + + initial + (initial * 2.0) + } + println(StructureND.toString(res)) + } + +} \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt index e43bbbc6f..a6ab55624 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ +@file:OptIn(PerformancePitfall::class) + package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64Array -- 2.34.1 From 24799a691f23805fba77342d31b9ced16617fc84 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 23 Nov 2021 10:32:51 +0300 Subject: [PATCH 6/9] Add inc/dec to counters --- .../space/kscience/kmath/histogram/Counter.kt | 26 ++++++++++++++++--- .../kmath/histogram/DoubleHistogramSpace.kt | 2 +- .../kmath/histogram/IndexedHistogramSpace.kt | 1 - .../kmath/histogram/TreeHistogramSpace.kt | 2 +- .../kmath/tensorflow/TensorFlowAlgebra.kt | 4 ++- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt index 4f5a1ceba..5755e05f7 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.histogram import kotlinx.atomicfu.atomic import kotlinx.atomicfu.getAndUpdate import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.Group /** * Common representation for atomic counters @@ -18,7 +18,7 @@ public interface Counter { public val value: T public companion object { - public fun real(): ObjectCounter = ObjectCounter(DoubleField) + public fun double(): ObjectCounter = ObjectCounter(DoubleField) } } @@ -32,6 +32,16 @@ public class IntCounter : Counter { override val value: Int get() = innerValue.value } +public operator fun IntCounter.inc(): IntCounter { + add(1) + return this +} + +public operator fun IntCounter.dec(): IntCounter { + add(-1) + return this +} + public class LongCounter : Counter { private val innerValue = atomic(0L) @@ -42,7 +52,17 @@ public class LongCounter : Counter { override val value: Long get() = innerValue.value } -public class ObjectCounter(public val group: Ring) : Counter { +public operator fun LongCounter.inc(): LongCounter { + add(1L) + return this +} + +public operator fun LongCounter.dec(): LongCounter { + add(-1L) + return this +} + +public class ObjectCounter(private val group: Group) : Counter { private val innerValue = atomic(group.zero) override fun add(delta: T) { diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt index c452edc9c..39121f301 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt @@ -74,7 +74,7 @@ public class DoubleHistogramSpace( } override fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram { - val ndCounter = StructureND.auto(shape) { Counter.real() } + val ndCounter = StructureND.auto(shape) { Counter.double() } val hBuilder = HistogramBuilder { point, value -> val index = getIndex(point) ndCounter[index].add(value.toDouble()) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt index f36f45389..cbf0bea1a 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt @@ -41,7 +41,6 @@ public class IndexedHistogram, V : Any>( get() = DefaultStrides(context.shape).asSequence().map { context.produceBin(it, values[it]) }.asIterable() - } /** diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt index cc54d7e1a..4103fa653 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt @@ -39,7 +39,7 @@ public class TreeHistogram( @PublishedApi internal class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain) : UnivariateHistogramBuilder { - internal class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : + internal class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.double()) : ClosedFloatingPointRange by domain.range private val bins: TreeMap = TreeMap() diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index 1f545d121..7ad91c267 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -232,4 +232,6 @@ public abstract class TensorFlowAlgebra> internal con @OptIn(UnstableKMathAPI::class) override fun export(arg: StructureND): StructureND = if (arg is TensorFlowOutput) arg.actualTensor else arg -} \ No newline at end of file +} + +//TODO add TensorFlow expressions \ No newline at end of file -- 2.34.1 From e11df4fdd5597e352eb558ea1aaa5071461e931a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 18 Dec 2021 21:57:06 +0300 Subject: [PATCH 7/9] Add inline to histogram builders --- .../space/kscience/kmath/histogram/UnivariateHistogram.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt index d5b74fb9b..91d0516c2 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt @@ -42,7 +42,7 @@ public interface UnivariateHistogram : Histogram { /** * Build and fill a [UnivariateHistogram]. Returns a read-only histogram. */ - public fun uniform( + public inline fun uniform( binSize: Double, start: Double = 0.0, builder: UnivariateHistogramBuilder.() -> Unit, @@ -51,7 +51,7 @@ public interface UnivariateHistogram : Histogram { /** * Build and fill a histogram with custom borders. Returns a read-only histogram. */ - public fun custom( + public inline fun custom( borders: DoubleArray, builder: UnivariateHistogramBuilder.() -> Unit, ): UnivariateHistogram = TreeHistogramSpace.custom(borders).fill(builder) -- 2.34.1 From 7bb66f6a00c8fa045e60a333bc5aae3d9cf5dfbd Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 29 Jan 2022 15:02:46 +0300 Subject: [PATCH 8/9] Add TensorFlow prototype --- CHANGELOG.md | 1 + README.md | 29 ------ docs/templates/README-TEMPLATE.md | 29 ------ gradle.properties | 2 +- kmath-tensorflow/build.gradle.kts | 4 +- .../tensorflow/DoubleTensorFlowAlgebra.kt | 21 ++++- .../kmath/tensorflow/TensorFlowAlgebra.kt | 90 +++++++++++-------- .../kscience/kmath/tensorflow/tfOperations.kt | 23 +++++ .../kmath/tensorflow/DoubleTensorFlowOps.kt | 18 +++- 9 files changed, 114 insertions(+), 103 deletions(-) create mode 100644 kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 857ed060b..a19b1f467 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Integration between `MST` and Symja `IExpr` - Complex power - Separate methods for UInt, Int and Number powers. NaN safety. +- Tensorflow prototype ### Changed - Exponential operations merged with hyperbolic functions diff --git a/README.md b/README.md index 8604873ae..92260716e 100644 --- a/README.md +++ b/README.md @@ -50,35 +50,6 @@ module definitions below. The module stability could have the following levels: with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ## Modules
diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index e75d4c5ed..b0c418697 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -50,35 +50,6 @@ module definitions below. The module stability could have the following levels: with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ## Modules $modules diff --git a/gradle.properties b/gradle.properties index 130d294a2..7dd9e6d61 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,4 +12,4 @@ org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G -toolsVersion=0.10.9-kotlin-1.6.10 +toolsVersion=0.11.1-kotlin-1.6.10 diff --git a/kmath-tensorflow/build.gradle.kts b/kmath-tensorflow/build.gradle.kts index c8307f01f..9380a7308 100644 --- a/kmath-tensorflow/build.gradle.kts +++ b/kmath-tensorflow/build.gradle.kts @@ -6,8 +6,8 @@ description = "Google tensorflow connector" dependencies { api(project(":kmath-tensors")) - api("org.tensorflow:tensorflow-core-api:0.3.3") - testImplementation("org.tensorflow:tensorflow-core-platform:0.3.3") + api("org.tensorflow:tensorflow-core-api:0.4.0") + testImplementation("org.tensorflow:tensorflow-core-platform:0.4.0") } readme { diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt index eb8245944..ecfd8d098 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.PowerOperations public class DoubleTensorFlowOutput( graph: Graph, @@ -23,7 +24,7 @@ public class DoubleTensorFlowOutput( public class DoubleTensorFlowAlgebra internal constructor( graph: Graph, -) : TensorFlowAlgebra(graph) { +) : TensorFlowAlgebra(graph), PowerOperations> { override val elementAlgebra: DoubleField get() = DoubleField @@ -57,9 +58,22 @@ public class DoubleTensorFlowAlgebra internal constructor( override fun const(value: Double): Constant = ops.constant(value) + override fun divide( + left: StructureND, + right: StructureND, + ): TensorFlowOutput = left.operate(right) { l, r -> + ops.math.div(l, r) + } + override fun power(arg: StructureND, pow: Number): TensorFlowOutput = + arg.operate { ops.math.pow(it, const(pow.toDouble())) } } +/** + * Compute a tensor with TensorFlow in a single run. + * + * The resulting tensor is available outside of scope + */ public fun DoubleField.produceWithTF( block: DoubleTensorFlowAlgebra.() -> StructureND, ): StructureND = Graph().use { graph -> @@ -67,6 +81,11 @@ public fun DoubleField.produceWithTF( scope.export(scope.block()) } +/** + * Compute several outputs with TensorFlow in a single run. + * + * The resulting tensors are available outside of scope + */ public fun DoubleField.produceMapWithTF( block: DoubleTensorFlowAlgebra.() -> Map>, ): Map> = Graph().use { graph -> diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index 7ad91c267..e2541a73e 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -12,6 +12,7 @@ import org.tensorflow.op.core.Max import org.tensorflow.op.core.Min import org.tensorflow.op.core.Sum import org.tensorflow.types.TInt32 +import org.tensorflow.types.family.TNumber import org.tensorflow.types.family.TType import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI @@ -29,6 +30,9 @@ internal val NdArray.scalar: T get() = getObject() public sealed interface TensorFlowTensor : Tensor +/** + * Static (eager) in-memory TensorFlow tensor + */ @JvmInline public value class TensorFlowArray(public val tensor: NdArray) : Tensor { override val shape: Shape get() = tensor.shape().asArray().toIntArray() @@ -42,6 +46,11 @@ public value class TensorFlowArray(public val tensor: NdArray) : Tensor } } +/** + * Lazy graph-based TensorFlow tensor. The tensor is actualized on call. + * + * If the tensor is used for intermediate operations, actualizing it could impact performance. + */ public abstract class TensorFlowOutput( protected val graph: Graph, output: Output, @@ -72,11 +81,11 @@ public abstract class TensorFlowOutput( } -public abstract class TensorFlowAlgebra> internal constructor( +public abstract class TensorFlowAlgebra> internal constructor( protected val graph: Graph, ) : TensorAlgebra { - protected val ops: Ops by lazy { Ops.create(graph) } + public val ops: Ops by lazy { Ops.create(graph) } protected abstract fun StructureND.asTensorFlow(): TensorFlowOutput @@ -87,7 +96,10 @@ public abstract class TensorFlowAlgebra> internal con override fun StructureND.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) get(Shape(0)) else null - private inline fun StructureND.biOp( + /** + * Perform binary lazy operation on tensor. Both arguments are implicitly converted + */ + public fun StructureND.operate( other: StructureND, operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { @@ -96,7 +108,7 @@ public abstract class TensorFlowAlgebra> internal con return operation(left, right).asOutput().wrap() } - private inline fun T.biOp( + public fun T.operate( other: StructureND, operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { @@ -105,7 +117,7 @@ public abstract class TensorFlowAlgebra> internal con return operation(left, right).asOutput().wrap() } - private inline fun StructureND.biOp( + public fun StructureND.operate( value: T, operation: (left: Operand, right: Operand) -> Operand, ): TensorFlowOutput { @@ -114,7 +126,7 @@ public abstract class TensorFlowAlgebra> internal con return operation(left, right).asOutput().wrap() } - private inline fun Tensor.inPlaceOp( + public fun Tensor.operateInPlace( other: StructureND, operation: (left: Operand, right: Operand) -> Operand, ): Unit { @@ -124,7 +136,7 @@ public abstract class TensorFlowAlgebra> internal con origin.output = operation(left, right).asOutput() } - private inline fun Tensor.inPlaceOp( + public fun Tensor.operateInPlace( value: T, operation: (left: Operand, right: Operand) -> Operand, ): Unit { @@ -134,61 +146,61 @@ public abstract class TensorFlowAlgebra> internal con origin.output = operation(left, right).asOutput() } - private inline fun StructureND.unOp(operation: (Operand) -> Operand): TensorFlowOutput = + public fun StructureND.operate(operation: (Operand) -> Operand): TensorFlowOutput = operation(asTensorFlow().output).asOutput().wrap() - override fun T.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) + override fun T.plus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::add) - override fun StructureND.plus(arg: T): TensorFlowOutput = biOp(arg, ops.math::add) + override fun StructureND.plus(arg: T): TensorFlowOutput = operate(arg, ops.math::add) - override fun StructureND.plus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::add) + override fun StructureND.plus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::add) - override fun Tensor.plusAssign(value: T): Unit = inPlaceOp(value, ops.math::add) + override fun Tensor.plusAssign(value: T): Unit = operateInPlace(value, ops.math::add) - override fun Tensor.plusAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::add) + override fun Tensor.plusAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::add) - override fun StructureND.minus(arg: T): TensorFlowOutput = biOp(arg, ops.math::sub) + override fun StructureND.minus(arg: T): TensorFlowOutput = operate(arg, ops.math::sub) - override fun StructureND.minus(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::sub) + override fun StructureND.minus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::sub) - override fun T.minus(arg: StructureND): Tensor = biOp(arg, ops.math::sub) + override fun T.minus(arg: StructureND): Tensor = operate(arg, ops.math::sub) - override fun Tensor.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub) + override fun Tensor.minusAssign(value: T): Unit = operateInPlace(value, ops.math::sub) - override fun Tensor.minusAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::sub) + override fun Tensor.minusAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::sub) - override fun T.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) + override fun T.times(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::mul) - override fun StructureND.times(arg: T): TensorFlowOutput = biOp(arg, ops.math::mul) + override fun StructureND.times(arg: T): TensorFlowOutput = operate(arg, ops.math::mul) - override fun StructureND.times(arg: StructureND): TensorFlowOutput = biOp(arg, ops.math::mul) + override fun StructureND.times(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::mul) - override fun Tensor.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul) + override fun Tensor.timesAssign(value: T): Unit = operateInPlace(value, ops.math::mul) - override fun Tensor.timesAssign(arg: StructureND): Unit = inPlaceOp(arg, ops.math::mul) + override fun Tensor.timesAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::mul) - override fun StructureND.unaryMinus(): TensorFlowOutput = unOp(ops.math::neg) + override fun StructureND.unaryMinus(): TensorFlowOutput = operate(ops.math::neg) - override fun Tensor.get(i: Int): Tensor = unOp { + override fun Tensor.get(i: Int): Tensor = operate { TODO("Not yet implemented") } - override fun Tensor.transpose(i: Int, j: Int): Tensor = unOp { + override fun Tensor.transpose(i: Int, j: Int): Tensor = operate { ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) } - override fun Tensor.view(shape: IntArray): Tensor = unOp { + override fun Tensor.view(shape: IntArray): Tensor = operate { ops.reshape(it, ops.constant(shape)) } - override fun Tensor.viewAs(other: StructureND): Tensor = biOp(other) { l, r -> + override fun Tensor.viewAs(other: StructureND): Tensor = operate(other) { l, r -> ops.reshape(l, ops.shape(r)) } - override fun StructureND.dot(other: StructureND): TensorFlowOutput = biOp(other) { l, r -> + override fun StructureND.dot(other: StructureND): TensorFlowOutput = operate(other) { l, r -> ops.linalg.matMul( - if (l.asTensor().shape().numDimensions() == 1) ops.expandDims(l,ops.constant(0)) else l, - if (r.asTensor().shape().numDimensions() == 1) ops.expandDims(r,ops.constant(-1)) else r) + if (l.asTensor().shape().numDimensions() == 1) ops.expandDims(l, ops.constant(0)) else l, + if (r.asTensor().shape().numDimensions() == 1) ops.expandDims(r, ops.constant(-1)) else r) } override fun diagonalEmbedding( @@ -196,31 +208,31 @@ public abstract class TensorFlowAlgebra> internal con offset: Int, dim1: Int, dim2: Int, - ): TensorFlowOutput = diagonalEntries.unOp { - TODO() + ): TensorFlowOutput = diagonalEntries.operate { + TODO("Not yet implemented") } - override fun StructureND.sum(): T = unOp { + override fun StructureND.sum(): T = operate { ops.sum(it, ops.constant(intArrayOf())) }.value() - override fun StructureND.sum(dim: Int, keepDim: Boolean): TensorFlowOutput = unOp { + override fun StructureND.sum(dim: Int, keepDim: Boolean): TensorFlowOutput = operate { ops.sum(it, ops.constant(dim), Sum.keepDims(keepDim)) } - override fun StructureND.min(): T = unOp { + override fun StructureND.min(): T = operate { ops.min(it, ops.constant(intArrayOf())) }.value() - override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor = unOp { + override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor = operate { ops.min(it, ops.constant(dim), Min.keepDims(keepDim)) } - override fun StructureND.max(): T = unOp { + override fun StructureND.max(): T = operate { ops.max(it, ops.constant(intArrayOf())) }.value() - override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor = unOp { + override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor = operate { ops.max(it, ops.constant(dim), Max.keepDims(keepDim)) } diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt new file mode 100644 index 000000000..257d4d6ea --- /dev/null +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt @@ -0,0 +1,23 @@ +/* + * 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.tensorflow + +import org.tensorflow.types.family.TNumber +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.TrigonometricOperations + +// + +// TODO add other operations + +public fun TensorFlowAlgebra.sin( + arg: StructureND, +): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.sin(it) } + +public fun TensorFlowAlgebra.cos( + arg: StructureND, +): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.cos(it) } diff --git a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt index b7a4b94b4..805ad7c66 100644 --- a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt +++ b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt @@ -1,9 +1,10 @@ package space.kscience.kmath.tensorflow import org.junit.jupiter.api.Test -import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.get import space.kscience.kmath.nd.structureND import space.kscience.kmath.operations.DoubleField +import kotlin.test.assertEquals class DoubleTensorFlowOps { @Test @@ -13,7 +14,20 @@ class DoubleTensorFlowOps { initial + (initial * 2.0) } - println(StructureND.toString(res)) + //println(StructureND.toString(res)) + assertEquals(3.0, res[0, 0]) } + @Test + fun extensionOps(){ + val res = DoubleField.produceWithTF { + val i = structureND(2, 2) { 0.5 } + + sin(i).pow(2) + cos(i).pow(2) + } + + assertEquals(1.0, res[0,0],0.01) + } + + } \ No newline at end of file -- 2.34.1 From d35516b9afc4bf7d213100b016920b8c92867083 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 2 Feb 2022 10:00:45 +0700 Subject: [PATCH 9/9] Fix theta --- .../commonMain/kotlin/space/kscience/kmath/complex/Complex.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt index d3c414838..77fe782a9 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt @@ -41,7 +41,7 @@ public val Complex.r: Double * An angle between vector represented by complex number and X axis. */ public val Complex.theta: Double - get() = atan(im / re) + get() = atan2(im, re) private val PI_DIV_2 = Complex(PI / 2, 0) -- 2.34.1