BufferedTensor revisited

This commit is contained in:
Roland Grinis 2021-03-15 22:11:15 +00:00
parent f8e0d4be17
commit 7cb5cd8f71
6 changed files with 78 additions and 62 deletions

View File

@ -1,32 +1,34 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.MutableNDBuffer
import space.kscience.kmath.structures.*
public open class BufferedTensor<T>(
override val shape: IntArray,
buffer: MutableBuffer<T>
) :
TensorStructure<T>,
MutableNDBuffer<T>(
TensorStrides(shape),
buffer
) {
public val buffer: MutableBuffer<T>,
internal val bufferStart: Int
) : TensorStructure<T>
{
public val strides: TensorStrides
get() = TensorStrides(shape)
override fun get(index: IntArray): T = buffer[bufferStart + strides.offset(index)]
public operator fun get(i: Int, j: Int): T {
check(this.dimension == 2) { "Not matrix" }
return this[intArrayOf(i, j)]
override fun set(index: IntArray, value: T) {
buffer[bufferStart + strides.offset(index)] = value
}
public operator fun set(i: Int, j: Int, value: T): Unit {
check(this.dimension == 2) { "Not matrix" }
this[intArrayOf(i, j)] = value
override fun elements(): Sequence<Pair<IntArray, T>> = strides.indices().map {
it to this[it]
}
override fun equals(other: Any?): Boolean = false
override fun hashCode(): Int = 0
}
/*
//todo make generator mb nextMatrixIndex?
public class InnerMatrix<T>(private val tensor: BufferedTensor<T>){
private var offset: Int = 0
@ -75,25 +77,29 @@ public class InnerVector<T>(private val tensor: BufferedTensor<T>){
offset += step
}
}
//todo default buffer = arrayOf(0)???
*/
public class IntTensor(
shape: IntArray,
buffer: IntArray
) : BufferedTensor<Int>(shape, IntBuffer(buffer))
buffer: IntArray,
offset: Int = 0
) : BufferedTensor<Int>(shape, IntBuffer(buffer), offset)
public class LongTensor(
shape: IntArray,
buffer: LongArray
) : BufferedTensor<Long>(shape, LongBuffer(buffer))
buffer: LongArray,
offset: Int = 0
) : BufferedTensor<Long>(shape, LongBuffer(buffer), offset)
public class FloatTensor(
shape: IntArray,
buffer: FloatArray
) : BufferedTensor<Float>(shape, FloatBuffer(buffer))
buffer: FloatArray,
offset: Int = 0
) : BufferedTensor<Float>(shape, FloatBuffer(buffer), offset)
public class DoubleTensor(
shape: IntArray,
buffer: DoubleArray
) : BufferedTensor<Double>(shape, RealBuffer(buffer))
buffer: DoubleArray,
offset: Int = 0
) : BufferedTensor<Double>(shape, RealBuffer(buffer), offset)

View File

@ -9,6 +9,7 @@ public class DoubleLinearOpsTensorAlgebra :
}
override fun DoubleTensor.lu(): Pair<DoubleTensor, IntTensor> {
/*
// todo checks
val luTensor = this.copy()
val lu = InnerMatrix(luTensor)
@ -69,11 +70,13 @@ public class DoubleLinearOpsTensorAlgebra :
pivot.makeStep()
}
return Pair(luTensor, pivotsTensor)
return Pair(luTensor, pivotsTensor)*/
TODO("Andrei, first we need to view and get(Int)")
}
override fun luPivot(lu: DoubleTensor, pivots: IntTensor): Triple<DoubleTensor, DoubleTensor, DoubleTensor> {
/*
// todo checks
val n = lu.shape[0]
val p = lu.zeroesLike()
@ -97,7 +100,8 @@ public class DoubleLinearOpsTensorAlgebra :
}
}
return Triple(p, l, u)
return Triple(p, l, u)*/
TODO("Andrei, first we need implement get(Int)")
}
override fun DoubleTensor.cholesky(): DoubleTensor {

View File

@ -7,11 +7,11 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double, Dou
check(this.shape contentEquals intArrayOf(1)) {
"Inconsistent value for tensor of shape ${shape.toList()}"
}
return this.buffer.unsafeToDoubleArray()[0]
return this.buffer.unsafeToDoubleArray()[this.bufferStart]
}
override fun DoubleTensor.get(i: Int): DoubleTensor {
TODO("Not yet implemented")
TODO("TOP PRIORITY")
}
override fun zeros(shape: IntArray): DoubleTensor {
@ -20,7 +20,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double, Dou
override fun DoubleTensor.zeroesLike(): DoubleTensor {
val shape = this.shape
val buffer = DoubleArray(this.buffer.size) { 0.0 }
val buffer = DoubleArray(this.strides.linearSize) { 0.0 }
return DoubleTensor(shape, buffer)
}
@ -31,6 +31,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double, Dou
override fun DoubleTensor.onesLike(): DoubleTensor {
TODO("Not yet implemented")
}
override fun eye(n: Int): DoubleTensor {
val shape = intArrayOf(n, n)
val buffer = DoubleArray(n * n) { 0.0 }
@ -42,14 +43,13 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double, Dou
}
override fun DoubleTensor.copy(): DoubleTensor {
// should be rework as soon as copy() method for NDBuffer will be available
return DoubleTensor(this.shape, this.buffer.unsafeToDoubleArray().copyOf())
return DoubleTensor(this.shape, this.buffer.unsafeToDoubleArray().copyOf(), this.bufferStart)
}
override fun Double.plus(other: DoubleTensor): DoubleTensor {
val resBuffer = DoubleArray(other.buffer.size) { i ->
other.buffer.unsafeToDoubleArray()[i] + this
val resBuffer = DoubleArray(other.strides.linearSize) { i ->
other.buffer.unsafeToDoubleArray()[other.bufferStart + i] + this
}
return DoubleTensor(other.shape, resBuffer)
}
@ -60,35 +60,36 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double, Dou
val broadcast = broadcastTensors(this, other)
val newThis = broadcast[0]
val newOther = broadcast[1]
val resBuffer = DoubleArray(newThis.buffer.size) { i ->
val resBuffer = DoubleArray(newThis.strides.linearSize) { i ->
newThis.buffer.unsafeToDoubleArray()[i] + newOther.buffer.unsafeToDoubleArray()[i]
}
return DoubleTensor(newThis.shape, resBuffer)
}
override fun DoubleTensor.plusAssign(value: Double) {
for (i in this.buffer.unsafeToDoubleArray().indices) {
this.buffer.unsafeToDoubleArray()[i] += value
for (i in 0 until this.strides.linearSize) {
this.buffer.unsafeToDoubleArray()[this.bufferStart + i] += value
}
}
override fun DoubleTensor.plusAssign(other: DoubleTensor) {
//todo should be change with broadcasting
for (i in this.buffer.unsafeToDoubleArray().indices) {
this.buffer.unsafeToDoubleArray()[i] += other.buffer.unsafeToDoubleArray()[i]
for (i in 0 until this.strides.linearSize) {
this.buffer.unsafeToDoubleArray()[this.bufferStart + i] +=
other.buffer.unsafeToDoubleArray()[this.bufferStart + i]
}
}
override fun Double.minus(other: DoubleTensor): DoubleTensor {
val resBuffer = DoubleArray(other.buffer.size) { i ->
this - other.buffer.unsafeToDoubleArray()[i]
val resBuffer = DoubleArray(other.strides.linearSize) { i ->
this - other.buffer.unsafeToDoubleArray()[other.bufferStart + i]
}
return DoubleTensor(other.shape, resBuffer)
}
override fun DoubleTensor.minus(value: Double): DoubleTensor {
val resBuffer = DoubleArray(this.buffer.size) { i ->
this.buffer.unsafeToDoubleArray()[i] - value
val resBuffer = DoubleArray(this.strides.linearSize) { i ->
this.buffer.unsafeToDoubleArray()[this.bufferStart + i] - value
}
return DoubleTensor(this.shape, resBuffer)
}
@ -97,15 +98,15 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double, Dou
val broadcast = broadcastTensors(this, other)
val newThis = broadcast[0]
val newOther = broadcast[1]
val resBuffer = DoubleArray(newThis.buffer.size) { i ->
val resBuffer = DoubleArray(newThis.strides.linearSize) { i ->
newThis.buffer.unsafeToDoubleArray()[i] - newOther.buffer.unsafeToDoubleArray()[i]
}
return DoubleTensor(newThis.shape, resBuffer)
}
override fun DoubleTensor.minusAssign(value: Double) {
for (i in this.buffer.unsafeToDoubleArray().indices) {
this.buffer.unsafeToDoubleArray()[i] -= value
for (i in 0 until this.strides.linearSize) {
this.buffer.unsafeToDoubleArray()[this.bufferStart + i] -= value
}
}
@ -115,8 +116,8 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double, Dou
override fun Double.times(other: DoubleTensor): DoubleTensor {
//todo should be change with broadcasting
val resBuffer = DoubleArray(other.buffer.size) { i ->
other.buffer.unsafeToDoubleArray()[i] * this
val resBuffer = DoubleArray(other.strides.linearSize) { i ->
other.buffer.unsafeToDoubleArray()[other.bufferStart + i] * this
}
return DoubleTensor(other.shape, resBuffer)
}
@ -126,36 +127,38 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double, Dou
override fun DoubleTensor.times(other: DoubleTensor): DoubleTensor {
//todo should be change with broadcasting
val resBuffer = DoubleArray(this.buffer.size) { i ->
this.buffer.unsafeToDoubleArray()[i] * other.buffer.unsafeToDoubleArray()[i]
val resBuffer = DoubleArray(this.strides.linearSize) { i ->
this.buffer.unsafeToDoubleArray()[other.bufferStart + i] *
other.buffer.unsafeToDoubleArray()[other.bufferStart + i]
}
return DoubleTensor(this.shape, resBuffer)
}
override fun DoubleTensor.timesAssign(value: Double) {
//todo should be change with broadcasting
for (i in this.buffer.unsafeToDoubleArray().indices) {
this.buffer.unsafeToDoubleArray()[i] *= value
for (i in 0 until this.strides.linearSize) {
this.buffer.unsafeToDoubleArray()[this.bufferStart + i] *= value
}
}
override fun DoubleTensor.timesAssign(other: DoubleTensor) {
//todo should be change with broadcasting
for (i in this.buffer.unsafeToDoubleArray().indices) {
this.buffer.unsafeToDoubleArray()[i] *= other.buffer.unsafeToDoubleArray()[i]
for (i in 0 until this.strides.linearSize) {
this.buffer.unsafeToDoubleArray()[this.bufferStart + i] *=
other.buffer.unsafeToDoubleArray()[this.bufferStart + i]
}
}
override fun DoubleTensor.unaryMinus(): DoubleTensor {
val resBuffer = DoubleArray(this.buffer.size) { i ->
this.buffer.unsafeToDoubleArray()[i].unaryMinus()
val resBuffer = DoubleArray(this.strides.linearSize) { i ->
this.buffer.unsafeToDoubleArray()[this.bufferStart + i].unaryMinus()
}
return DoubleTensor(this.shape, resBuffer)
}
override fun DoubleTensor.transpose(i: Int, j: Int): DoubleTensor {
checkTranspose(this.dimension, i, j)
val n = this.buffer.size
val n = this.strides.linearSize
val resBuffer = DoubleArray(n)
val resShape = this.shape.copyOf()
@ -169,14 +172,16 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double, Dou
newMultiIndex[i] = newMultiIndex[j].also { newMultiIndex[j] = newMultiIndex[i] }
val linearIndex = resTensor.strides.offset(newMultiIndex)
resTensor.buffer.unsafeToDoubleArray()[linearIndex] = this.buffer.unsafeToDoubleArray()[offset]
resTensor.buffer.unsafeToDoubleArray()[linearIndex] =
this.buffer.unsafeToDoubleArray()[this.bufferStart + offset]
}
return resTensor
}
override fun DoubleTensor.view(shape: IntArray): DoubleTensor {
return DoubleTensor(shape, this.buffer.unsafeToDoubleArray())
checkView(this, shape)
return DoubleTensor(shape, this.buffer.unsafeToDoubleArray(), this.bufferStart)
}
override fun DoubleTensor.viewAs(other: DoubleTensor): DoubleTensor {

View File

@ -55,7 +55,8 @@ internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List<DoubleT
}
val curLinearIndex = tensor.strides.offset(curMultiIndex)
resTensor.buffer.unsafeToDoubleArray()[linearIndex] = tensor.buffer.unsafeToDoubleArray()[curLinearIndex]
resTensor.buffer.unsafeToDoubleArray()[linearIndex] =
tensor.buffer.unsafeToDoubleArray()[tensor.bufferStart + curLinearIndex]
}
res.add(resTensor)
}

View File

@ -6,7 +6,7 @@ import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class TestRealTensor {
class TestDoubleTensor {
@Test
fun valueTest() = DoubleTensorAlgebra {

View File

@ -4,7 +4,7 @@ package space.kscience.kmath.tensors
import kotlin.test.Test
import kotlin.test.assertTrue
class TestRealTensorAlgebra {
class TestDoubleTensorAlgebra {
@Test
fun doublePlus() = DoubleTensorAlgebra {