Golub-Kahan SVD algorithm for KMP tensors #499

Closed
grinisrit wants to merge 64 commits from dev into dev
Showing only changes of commit 38ed6dd995 - Show all commits

View File

@ -8,27 +8,134 @@ import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope import kotlinx.benchmark.Scope
import kotlinx.benchmark.State 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.svdGolubKahan
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.transpose
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.svdPowerMethod import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.svdPowerMethod
@State(Scope.Benchmark) @State(Scope.Benchmark)
class SVDBenchmark { class SVDBenchmark {
companion object { 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 @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( blackhole.consume(
tensor.svdPowerMethod() tensorSmall.svdPowerMethod()
) )
} }
@Benchmark @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( 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()
) )
} }
} }