From 559e8b24ab6189b523e3707b605b7f2c75c8b92c Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Wed, 21 Apr 2021 23:44:39 +0300 Subject: [PATCH] rework structure + fixes --- .../{ => api}/AnalyticTensorAlgebra.kt | 7 +- .../{ => api}/LinearOpsTensorAlgebra.kt | 7 +- .../kmath/tensors/{ => api}/TensorAlgebra.kt | 11 +- .../{ => api}/TensorPartialDivisionAlgebra.kt | 9 +- .../tensors/{ => api}/TensorStructure.kt | 2 +- .../kmath/tensors/core/BufferedTensor.kt | 3 +- .../algebras/BroadcastDoubleTensorAlgebra.kt | 89 ++++++++++ .../DoubleAnalyticTensorAlgebra.kt | 13 +- .../DoubleLinearOpsTensorAlgebra.kt | 27 +++- .../{ => algebras}/DoubleTensorAlgebra.kt | 27 +++- .../{ => algebras}/TensorLinearStructure.kt | 7 +- ...ubleTensorAlgebra.kt => broadcastUtils.kt} | 153 ++++-------------- .../kscience/kmath/tensors/core/checks.kt | 4 +- .../tensors/core/{linutils.kt => linUtils.kt} | 10 +- .../kscience/kmath/tensors/core/utils.kt | 1 - .../kmath/tensors/core/TestBroadcasting.kt | 1 + .../core/TestDoubleAnalyticTensorAlgebra.kt | 1 + .../core/TestDoubleLinearOpsAlgebra.kt | 3 +- .../kmath/tensors/core/TestDoubleTensor.kt | 2 +- .../tensors/core/TestDoubleTensorAlgebra.kt | 20 ++- 20 files changed, 237 insertions(+), 160 deletions(-) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/AnalyticTensorAlgebra.kt (91%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/LinearOpsTensorAlgebra.kt (86%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/TensorAlgebra.kt (89%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/TensorPartialDivisionAlgebra.kt (64%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/TensorStructure.kt (73%) create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => algebras}/DoubleAnalyticTensorAlgebra.kt (77%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => algebras}/DoubleLinearOpsTensorAlgebra.kt (84%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => algebras}/DoubleTensorAlgebra.kt (92%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => algebras}/TensorLinearStructure.kt (90%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{BroadcastDoubleTensorAlgebra.kt => broadcastUtils.kt} (52%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{linutils.kt => linUtils.kt} (97%) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt similarity index 91% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index 2a8b228f4..315f39027 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -1,4 +1,9 @@ -package space.kscience.kmath.tensors +/* + * 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.tensors.api public interface AnalyticTensorAlgebra : diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt similarity index 86% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 8ca8945a5..5cd48ca78 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -1,4 +1,9 @@ -package space.kscience.kmath.tensors +/* + * 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.tensors.api public interface LinearOpsTensorAlgebra : diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt similarity index 89% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index f64d49dd8..c1657d916 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -1,4 +1,9 @@ -package space.kscience.kmath.tensors +/* + * 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.tensors.api // https://proofwiki.org/wiki/Definition:Algebra_over_Ring public interface TensorAlgebra { @@ -40,7 +45,9 @@ public interface TensorAlgebra { //https://pytorch.org/docs/stable/generated/torch.diag_embed.html public fun diagonalEmbedding( diagonalEntries: TensorStructure, - offset: Int = 0, dim1: Int = -2, dim2: Int = -1 + offset: Int = 0, + dim1: Int = -2, + dim2: Int = -1 ): TensorStructure } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt similarity index 64% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index b37ac6b6e..075e86e61 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -1,8 +1,13 @@ -package space.kscience.kmath.tensors +/* + * 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.tensors.api // https://proofwiki.org/wiki/Definition:Division_Algebra public interface TensorPartialDivisionAlgebra : - TensorAlgebra { + TensorAlgebra { public operator fun TensorStructure.div(value: T): TensorStructure public operator fun TensorStructure.div(other: TensorStructure): TensorStructure public operator fun TensorStructure.divAssign(value: T) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorStructure.kt similarity index 73% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorStructure.kt index 64c4d98b8..edecd6383 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorStructure.kt @@ -1,4 +1,4 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.api import space.kscience.kmath.nd.MutableStructureND diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 2b61e10b2..5c0d9c4ea 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -1,7 +1,8 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.structures.* -import space.kscience.kmath.tensors.TensorStructure +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure public open class BufferedTensor( diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt new file mode 100644 index 000000000..1b00197ff --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt @@ -0,0 +1,89 @@ +/* + * 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.tensors.core.algebras + +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.broadcastTensors +import space.kscience.kmath.tensors.core.broadcastTo + +public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { + + override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + newThis.buffer.array()[i] + newOther.buffer.array()[i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun TensorStructure.plusAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] += + newOther.buffer.array()[tensor.bufferStart + i] + } + } + + override fun TensorStructure.minus(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + newThis.buffer.array()[i] - newOther.buffer.array()[i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun TensorStructure.minusAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] -= + newOther.buffer.array()[tensor.bufferStart + i] + } + } + + override fun TensorStructure.times(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + newThis.buffer.array()[newThis.bufferStart + i] * + newOther.buffer.array()[newOther.bufferStart + i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun TensorStructure.timesAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] *= + newOther.buffer.array()[tensor.bufferStart + i] + } + } + + override fun TensorStructure.div(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + newThis.buffer.array()[newOther.bufferStart + i] / + newOther.buffer.array()[newOther.bufferStart + i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun TensorStructure.divAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] /= + newOther.buffer.array()[tensor.bufferStart + i] + } + } + +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt similarity index 77% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt index 233217f2f..7d1cceb15 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt @@ -1,7 +1,14 @@ -package space.kscience.kmath.tensors.core +/* + * 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. + */ -import space.kscience.kmath.tensors.AnalyticTensorAlgebra -import space.kscience.kmath.tensors.TensorStructure +package space.kscience.kmath.tensors.core.algebras + +import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.tensor import kotlin.math.* public class DoubleAnalyticTensorAlgebra: diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt similarity index 84% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index 386fc2a1b..62629f3db 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -1,9 +1,23 @@ -package space.kscience.kmath.tensors.core +/* + * 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. + */ -import space.kscience.kmath.tensors.LinearOpsTensorAlgebra +package space.kscience.kmath.tensors.core.algebras + +import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D -import space.kscience.kmath.tensors.TensorStructure +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.checkSquareMatrix +import space.kscience.kmath.tensors.core.choleskyHelper +import space.kscience.kmath.tensors.core.cleanSymHelper +import space.kscience.kmath.tensors.core.luHelper +import space.kscience.kmath.tensors.core.luMatrixDet +import space.kscience.kmath.tensors.core.luMatrixInv +import space.kscience.kmath.tensors.core.luPivotHelper +import space.kscience.kmath.tensors.core.pivInit import kotlin.math.min @@ -25,12 +39,11 @@ public class DoubleLinearOpsTensorAlgebra : luTensor: TensorStructure, pivotsTensor: TensorStructure ): Triple { - //todo checks checkSquareMatrix(luTensor.shape) check( luTensor.shape.dropLast(2).toIntArray() contentEquals pivotsTensor.shape.dropLast(1).toIntArray() || luTensor.shape.last() == pivotsTensor.shape.last() - 1 - ) { "Bad shapes ((" } //todo rewrite + ) { "Inappropriate shapes of input tensors" } val n = luTensor.shape.last() val pTensor = luTensor.zeroesLike() @@ -90,10 +103,10 @@ public class DoubleLinearOpsTensorAlgebra : for ((matrix, USV) in tensor.matrixSequence() .zip(resU.matrixSequence().zip(resS.vectorSequence().zip(resV.matrixSequence())))) { - val size = matrix.shape.reduce { acc, i -> acc * i } + val matrixSize = matrix.shape.reduce { acc, i -> acc * i } val curMatrix = DoubleTensor( matrix.shape, - matrix.buffer.array().slice(matrix.bufferStart until matrix.bufferStart + size).toDoubleArray() + matrix.buffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize).toDoubleArray() ) svdHelper(curMatrix, USV, m, n, epsilon) } 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/algebras/DoubleTensorAlgebra.kt similarity index 92% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 7544bf68e..651db2c21 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/algebras/DoubleTensorAlgebra.kt @@ -1,8 +1,24 @@ -package space.kscience.kmath.tensors.core +/* + * 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.tensors.core.algebras import space.kscience.kmath.nd.as2D -import space.kscience.kmath.tensors.TensorPartialDivisionAlgebra -import space.kscience.kmath.tensors.TensorStructure +import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.broadcastOuterTensors +import space.kscience.kmath.tensors.core.checkBufferShapeConsistency +import space.kscience.kmath.tensors.core.checkEmptyDoubleBuffer +import space.kscience.kmath.tensors.core.checkEmptyShape +import space.kscience.kmath.tensors.core.checkShapesCompatible +import space.kscience.kmath.tensors.core.checkTranspose +import space.kscience.kmath.tensors.core.checkView +import space.kscience.kmath.tensors.core.dotHelper +import space.kscience.kmath.tensors.core.getRandomNormals +import space.kscience.kmath.tensors.core.minusIndexFrom import kotlin.math.abs public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { @@ -263,7 +279,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { if (m1 != m2) { throw RuntimeException("Tensors dot operation dimension mismatch: ($l, $m1) x ($m2, $n)") } - val m = m1 val resShape = newThis.shape.sliceArray(0..(newThis.shape.size - 2)) + intArrayOf(newOther.shape.last()) val resSize = resShape.reduce { acc, i -> acc * i } @@ -271,7 +286,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { val (a, b) = ab - dotHelper(a.as2D(), b.as2D(), res.as2D(), l, m, n) + dotHelper(a.as2D(), b.as2D(), res.as2D(), l, m1, n) } if (penultimateDim) { @@ -347,7 +362,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return tensor.eq(other) { x, y -> abs(x - y) < delta } } - public fun TensorStructure.eq(other: TensorStructure): Boolean = tensor.eq(other, 1e-5) + public infix fun TensorStructure.eq(other: TensorStructure): Boolean = tensor.eq(other, 1e-5) private fun TensorStructure.eq( other: TensorStructure, diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt similarity index 90% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt index 47745c2be..b16739892 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt @@ -1,4 +1,9 @@ -package space.kscience.kmath.tensors.core +/* + * 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.tensors.core.algebras import kotlin.math.max diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt similarity index 52% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt index 53c385197..4378e9ac9 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt @@ -1,89 +1,31 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.tensors.TensorStructure +import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra import kotlin.math.max -public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - - override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[i] + newOther.buffer.array()[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun TensorStructure.plusAssign(other: TensorStructure) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] += - newOther.buffer.array()[tensor.bufferStart + i] - } - } - - override fun TensorStructure.minus(other: TensorStructure): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[i] - newOther.buffer.array()[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun TensorStructure.minusAssign(other: TensorStructure) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] -= - newOther.buffer.array()[tensor.bufferStart + i] - } - } - - override fun TensorStructure.times(other: TensorStructure): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[newThis.bufferStart + i] * - newOther.buffer.array()[newOther.bufferStart + i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun TensorStructure.timesAssign(other: TensorStructure) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] *= - newOther.buffer.array()[tensor.bufferStart + i] - } - } - - override fun TensorStructure.div(other: TensorStructure): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[newOther.bufferStart + i] / - newOther.buffer.array()[newOther.bufferStart + i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun TensorStructure.divAssign(other: TensorStructure) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] /= - newOther.buffer.array()[tensor.bufferStart + i] - } - } - -} - public inline fun BroadcastDoubleTensorAlgebra(block: BroadcastDoubleTensorAlgebra.() -> R): R = BroadcastDoubleTensorAlgebra().block() +internal inline fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { + for (linearIndex in 0 until linearSize) { + val totalMultiIndex = resTensor.linearStructure.index(linearIndex) + val curMultiIndex = tensor.shape.copyOf() + + val offset = totalMultiIndex.size - curMultiIndex.size + + for (i in curMultiIndex.indices) { + if (curMultiIndex[i] != 1) { + curMultiIndex[i] = totalMultiIndex[i + offset] + } else { + curMultiIndex[i] = 0 + } + } + + val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) + resTensor.buffer.array()[linearIndex] = + tensor.buffer.array()[tensor.bufferStart + curLinearIndex] + } +} internal inline fun broadcastShapes(vararg shapes: IntArray): IntArray { var totalDim = 0 @@ -129,24 +71,7 @@ internal inline fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): Doubl } } - for (linearIndex in 0 until n) { - val totalMultiIndex = resTensor.linearStructure.index(linearIndex) - val curMultiIndex = tensor.shape.copyOf() - - val offset = totalMultiIndex.size - curMultiIndex.size - - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i + offset] - } else { - curMultiIndex[i] = 0 - } - } - - val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) - resTensor.buffer.array()[linearIndex] = - tensor.buffer.array()[tensor.bufferStart + curLinearIndex] - } + multiIndexBroadCasting(tensor, resTensor, n) return resTensor } @@ -157,25 +82,7 @@ internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List(0) for (tensor in tensors) { val resTensor = DoubleTensor(totalShape, DoubleArray(n)) - - for (linearIndex in 0 until n) { - val totalMultiIndex = resTensor.linearStructure.index(linearIndex) - val curMultiIndex = tensor.shape.copyOf() - - val offset = totalMultiIndex.size - curMultiIndex.size - - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i + offset] - } else { - curMultiIndex[i] = 0 - } - } - - val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) - resTensor.buffer.array()[linearIndex] = - tensor.buffer.array()[tensor.bufferStart + curLinearIndex] - } + multiIndexBroadCasting(tensor, resTensor, n) res.add(resTensor) } @@ -208,7 +115,7 @@ internal inline fun broadcastOuterTensors(vararg tensors: DoubleTensor): List BufferedTensor.matrixSequence(): Sequence BufferedTensor.forEachVector(vectorAction: (BufferedTensor) -> Unit): Unit { +internal inline fun BufferedTensor.forEachVector(vectorAction: (BufferedTensor) -> Unit) { for (vector in vectorSequence()) { vectorAction(vector) } } -internal inline fun BufferedTensor.forEachMatrix(matrixAction: (BufferedTensor) -> Unit): Unit { +internal inline fun BufferedTensor.forEachMatrix(matrixAction: (BufferedTensor) -> Unit) { for (matrix in matrixSequence()) { matrixAction(matrix) } @@ -284,7 +286,7 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( matrix: DoubleTensor, USV: Pair, Pair, BufferedTensor>>, m: Int, n: Int, epsilon: Double -): Unit { +) { val res = ArrayList>(0) val (matrixU, SV) = USV val (matrixS, matrixV) = SV @@ -332,7 +334,7 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( } } -internal inline fun cleanSymHelper(matrix: MutableStructure2D, n: Int): Unit { +internal inline fun cleanSymHelper(matrix: MutableStructure2D, n: Int) { for (i in 0 until n) for (j in 0 until n) { if (i == j) { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index ac823185b..d7d006e42 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -110,7 +110,6 @@ internal inline fun DoubleTensor.toPrettyString(): String = buildString { charOffset -=1 } offset += vectorSize - // todo refactor if (this@toPrettyString.numElements == offset) { break } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 41c9b72f7..d677f6966 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.test.Test import kotlin.test.assertTrue diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 4dcdb7848..060bc1607 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import kotlin.math.abs import kotlin.math.exp import kotlin.test.Test diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index d19d0b6f6..6120f0e4a 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra import kotlin.math.abs import kotlin.test.Test import kotlin.test.assertEquals @@ -125,8 +126,6 @@ class TestDoubleLinearOpsTensorAlgebra { val (lu, pivots) = tensor.lu() - // todo check lu - val (p, l, u) = luPivot(lu, pivots) assertTrue { p.shape contentEquals shape } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 4de69e1ad..5c068ce83 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -3,7 +3,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.structures.toDoubleArray -import kotlin.test.Ignore +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index fa7a8fd32..10a9176dc 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -1,7 +1,9 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.test.Test +import kotlin.test.assertFalse import kotlin.test.assertTrue class TestDoubleTensorAlgebra { @@ -133,9 +135,9 @@ class TestDoubleTensorAlgebra { assertTrue(diagonal1.buffer.array() contentEquals doubleArrayOf(10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0)) - val diagonal1_offset = diagonalEmbedding(tensor1, 1, 1, 0) - assertTrue(diagonal1_offset.shape contentEquals intArrayOf(4, 4)) - assertTrue(diagonal1_offset.buffer.array() contentEquals + val diagonal1Offset = diagonalEmbedding(tensor1, 1, 1, 0) + assertTrue(diagonal1Offset.shape contentEquals intArrayOf(4, 4)) + assertTrue(diagonal1Offset.buffer.array() contentEquals doubleArrayOf(0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 30.0, 0.0)) val diagonal2 = diagonalEmbedding(tensor2, 1, 0, 2) @@ -149,7 +151,15 @@ class TestDoubleTensorAlgebra { } @Test - fun testContentEqual() = DoubleTensorAlgebra { - //TODO() + fun testEq() = DoubleTensorAlgebra { + val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + val tensor3 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0)) + val tensor4 = fromArray(intArrayOf(6, 1), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + + assertTrue(tensor1 eq tensor1) + assertTrue(tensor1 eq tensor2) + assertFalse(tensor1.eq(tensor3)) + } } \ No newline at end of file