Golub-Kahan SVD algorithm for KMP tensors #499
@ -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()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user