KMP library for tensors #300
@ -68,6 +68,16 @@ public interface AnalyticTensorAlgebra<T> :
|
|||||||
*/
|
*/
|
||||||
public fun Tensor<T>.variance(dim: Int, keepDim: Boolean): Tensor<T>
|
public fun Tensor<T>.variance(dim: Int, keepDim: Boolean): Tensor<T>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the covariance matrix M of given vectors.
|
||||||
|
*
|
||||||
|
* M[i, j] contains covariance of i-th and j-th given vectors
|
||||||
|
*
|
||||||
|
* @param tensors the [List] of 1-dimensional tensors with same shape
|
||||||
|
* @return the covariance matrix
|
||||||
|
*/
|
||||||
|
public fun cov(tensors: List<Tensor<T>>): Tensor<T>
|
||||||
|
|
||||||
//For information: https://pytorch.org/docs/stable/generated/torch.exp.html
|
//For information: https://pytorch.org/docs/stable/generated/torch.exp.html
|
||||||
public fun Tensor<T>.exp(): Tensor<T>
|
public fun Tensor<T>.exp(): Tensor<T>
|
||||||
|
|
||||||
|
@ -57,6 +57,28 @@ public object DoubleAnalyticTensorAlgebra :
|
|||||||
keepDim
|
keepDim
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun cov(x: DoubleTensor, y:DoubleTensor): Double{
|
||||||
|
val n = x.shape[0]
|
||||||
|
return ((x - x.mean()) * (y - y.mean())).mean() * n / (n - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cov(tensors: List<Tensor<Double>>): DoubleTensor {
|
||||||
|
check(tensors.isNotEmpty()) { "List must have at least 1 element" }
|
||||||
|
val n = tensors.size
|
||||||
|
val m = tensors[0].shape[0]
|
||||||
|
check(tensors.all { it.shape contentEquals intArrayOf(m) }) { "Tensors must have same shapes" }
|
||||||
|
val resTensor = DoubleTensor(
|
||||||
|
intArrayOf(n, n),
|
||||||
|
DoubleArray(n * n) {0.0}
|
||||||
|
)
|
||||||
|
for (i in 0 until n){
|
||||||
|
for (j in 0 until n){
|
||||||
|
resTensor[intArrayOf(i, j)] = cov(tensors[i].tensor, tensors[j].tensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resTensor
|
||||||
|
}
|
||||||
|
|
||||||
override fun Tensor<Double>.exp(): DoubleTensor = tensor.map(::exp)
|
override fun Tensor<Double>.exp(): DoubleTensor = tensor.map(::exp)
|
||||||
|
|
||||||
override fun Tensor<Double>.ln(): DoubleTensor = tensor.map(::ln)
|
override fun Tensor<Double>.ln(): DoubleTensor = tensor.map(::ln)
|
||||||
@ -91,4 +113,4 @@ public object DoubleAnalyticTensorAlgebra :
|
|||||||
|
|
||||||
override fun Tensor<Double>.floor(): DoubleTensor = tensor.map(::floor)
|
override fun Tensor<Double>.floor(): DoubleTensor = tensor.map(::floor)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -456,19 +456,31 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double> {
|
|||||||
public fun Tensor<Double>.randomNormalLike(seed: Long = 0): DoubleTensor =
|
public fun Tensor<Double>.randomNormalLike(seed: Long = 0): DoubleTensor =
|
||||||
DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed))
|
DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed))
|
||||||
|
|
||||||
// stack tensors by axis 0
|
/**
|
||||||
public fun stack(tensors: List<DoubleTensor>): DoubleTensor {
|
* Concatenates a sequence of tensors along a new dimension.
|
||||||
val shape = tensors.firstOrNull()?.shape
|
*
|
||||||
check(shape != null) { "Collection must have at least 1 element" }
|
* @param tensors the [List] of tensors with same shapes to concatenate
|
||||||
check(tensors.all { it.shape contentEquals shape }) { "Stacking tensors must have same shapes" }
|
* @param dim the dimension to insert
|
||||||
|
* @return tensor with concatenation result
|
||||||
|
*/
|
||||||
|
public fun stack(tensors: List<Tensor<Double>>, dim: Int = 0): DoubleTensor {
|
||||||
|
check(dim == 0) { "Stack by non-zero dimension not implemented yet" }
|
||||||
|
check(tensors.isNotEmpty()) { "List must have at least 1 element" }
|
||||||
|
val shape = tensors[0].shape
|
||||||
|
check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" }
|
||||||
val resShape = intArrayOf(tensors.size) + shape
|
val resShape = intArrayOf(tensors.size) + shape
|
||||||
val resBuffer = tensors.flatMap {
|
val resBuffer = tensors.flatMap {
|
||||||
it.tensor.mutableBuffer.array().drop(it.bufferStart).take(it.numElements)
|
it.tensor.mutableBuffer.array().drop(it.tensor.bufferStart).take(it.tensor.numElements)
|
||||||
}.toDoubleArray()
|
}.toDoubleArray()
|
||||||
return DoubleTensor(resShape, resBuffer, 0)
|
return DoubleTensor(resShape, resBuffer, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// build tensor from this rows by given indices
|
/**
|
||||||
|
* Build tensor from rows of input tensor
|
||||||
|
*
|
||||||
|
* @param indices the [IntArray] of 1-dimensional indices
|
||||||
|
* @return tensor with rows corresponding to rows by [indices]
|
||||||
|
*/
|
||||||
public fun Tensor<Double>.rowsByIndices(indices: IntArray): DoubleTensor {
|
public fun Tensor<Double>.rowsByIndices(indices: IntArray): DoubleTensor {
|
||||||
return stack(indices.map { this[it] })
|
return stack(indices.map { this[it] })
|
||||||
}
|
}
|
||||||
@ -505,7 +517,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra<Double> {
|
|||||||
override fun Tensor<Double>.sum(dim: Int, keepDim: Boolean): DoubleTensor =
|
override fun Tensor<Double>.sum(dim: Int, keepDim: Boolean): DoubleTensor =
|
||||||
foldDim({ x -> x.sum() }, dim, keepDim)
|
foldDim({ x -> x.sum() }, dim, keepDim)
|
||||||
|
|
||||||
|
|
||||||
override fun Tensor<Double>.min(): Double = this.fold { it.minOrNull()!! }
|
override fun Tensor<Double>.min(): Double = this.fold { it.minOrNull()!! }
|
||||||
|
|
||||||
override fun Tensor<Double>.min(dim: Int, keepDim: Boolean): DoubleTensor =
|
override fun Tensor<Double>.min(dim: Int, keepDim: Boolean): DoubleTensor =
|
||||||
|
Loading…
Reference in New Issue
Block a user