Golub-Kahan SVD algorithm for KMP tensors #499
@ -8,27 +8,134 @@ import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import org.ejml.UtilEjml.assertTrue
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.diagonalEmbedding
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.dot
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.eq
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.svdGolubKahan
|
||||
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.transpose
|
||||
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
|
||||
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.svdPowerMethod
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
class SVDBenchmark {
|
||||
companion object {
|
||||
val tensor = DoubleTensorAlgebra.randomNormal(intArrayOf(10, 10, 10), 0)
|
||||
val tensorSmall = DoubleTensorAlgebra.randomNormal(intArrayOf(5, 5), 0)
|
||||
val tensorMedium = DoubleTensorAlgebra.randomNormal(intArrayOf(10, 10), 0)
|
||||
val tensorLarge = DoubleTensorAlgebra.randomNormal(intArrayOf(50, 50), 0)
|
||||
val tensorVeryLarge = DoubleTensorAlgebra.randomNormal(intArrayOf(100, 100), 0)
|
||||
val epsilon = 1e-9
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdPowerMethod(blackhole: Blackhole) {
|
||||
fun svdPowerMethodSmall(blackhole: Blackhole) {
|
||||
val svd = tensorSmall.svdPowerMethod()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorSmall, epsilon))
|
||||
blackhole.consume(
|
||||
tensor.svdPowerMethod()
|
||||
tensorSmall.svdPowerMethod()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdGolubKahan(blackhole: Blackhole) {
|
||||
fun svdPowerMethodMedium(blackhole: Blackhole) {
|
||||
val svd = tensorMedium.svdPowerMethod()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorMedium, epsilon))
|
||||
blackhole.consume(
|
||||
tensor.svdGolubKahan()
|
||||
tensorMedium.svdPowerMethod()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdPowerMethodLarge(blackhole: Blackhole) {
|
||||
val svd = tensorLarge.svdPowerMethod()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorLarge, epsilon))
|
||||
blackhole.consume(
|
||||
tensorLarge.svdPowerMethod()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdPowerMethodVeryLarge(blackhole: Blackhole) {
|
||||
val svd = tensorVeryLarge.svdPowerMethod()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorVeryLarge, epsilon))
|
||||
blackhole.consume(
|
||||
tensorVeryLarge.svdPowerMethod()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdGolubKahanSmall(blackhole: Blackhole) {
|
||||
val svd = tensorSmall.svdGolubKahan()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorSmall, epsilon))
|
||||
blackhole.consume(
|
||||
tensorSmall.svdGolubKahan()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdGolubKahanMedium(blackhole: Blackhole) {
|
||||
val svd = tensorMedium.svdGolubKahan()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorMedium, epsilon))
|
||||
blackhole.consume(
|
||||
tensorMedium.svdGolubKahan()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdGolubKahanLarge(blackhole: Blackhole) {
|
||||
val svd = tensorLarge.svdGolubKahan()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorLarge, epsilon))
|
||||
blackhole.consume(
|
||||
tensorLarge.svdGolubKahan()
|
||||
)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun svdGolubKahanVeryLarge(blackhole: Blackhole) {
|
||||
val svd = tensorVeryLarge.svdGolubKahan()
|
||||
val tensorSVD = svd.first
|
||||
.dot(
|
||||
diagonalEmbedding(svd.second)
|
||||
.dot(svd.third.transpose())
|
||||
)
|
||||
assertTrue(tensorSVD.eq(tensorVeryLarge, epsilon))
|
||||
blackhole.consume(
|
||||
tensorVeryLarge.svdGolubKahan()
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user