gonum: mat: performance of calculating eigenvalues in gonum is slower than numpy
What are you trying to do?
I am comparing the performance of certain numpy operations against gonum for equivalency. In this specific benchmark I am assessing the performance of calculating the eigenvalues of a matrix to determine whether the matrix is positive definite.
What did you do?
I ran the following scripts in Python and Go respectively:
import numpy as np
def is_pos_def(x):
return np.all(np.linalg.eigvals(x) > 0)
a = np.random.rand(1000, 1000)
print is_pos_def(a)
package main
import (
"fmt"
"math/rand"
"gonum.org/v1/gonum/mat"
)
func randMat(d int) mat.Matrix {
data := make([]float64, d*d)
for i := range data {
data[i] = rand.NormFloat64()
}
return mat.NewDense(d, d, data)
}
func isPosDef(x mat.Matrix) bool {
var eig mat.Eigen
eig.Factorize(x, false, false)
allGreaterThanZero := true
for _, v := range eig.Values(nil) {
if real(v) <= 0.0 {
allGreaterThanZero = false
break
}
}
return allGreaterThanZero
}
func main() {
a := randMat(1000)
fmt.Println(isPosDef(a))
}
What did you expect to happen?
I expected the Go script to run equally fast as the Python script
What actually happened?
The Go script runs about 5x slower than the Python script:
python demo.py 1.36s user 0.12s system 135% cpu 1.092 total
go run demo.go 6.04s user 0.26s system 129% cpu 4.855 total
The Go script runs about 16x slower when left and/or right are set to true when calculating the eigenvector factorization. Am I setting up the Go code incorrectly at all or is there something degrading performance in the library implementation?
What version of Go and Gonum are you using?
$ go version
go version go1.10 darwin/amd64
gonum$ git rev-parse HEAD
c75679ee1eff8582bca7583704825721ea1ff701
About this issue
- Original URL
- State: open
- Created 6 years ago
- Comments: 16 (8 by maintainers)
In conjunction with the installation of the “gonum.org/v1/netlib/lapack/netlib” package (needs CGO and is built according to instruction at the link above), you need to change your imports to include
and
mainto behttps://github.com/gonum/netlib
Not only
Dlaqr5, this will swap out the whole eigen solver, the entry routine isDgeev.If you need to check whether your matrix is positive definite, then you are most likely assessing performance of the wrong eigen solver.
Checking the pprof output from @sbinet , it seems that most time in Dlaqr5 is spent on lines doing just index calculations and accessing slices. The next step would be to look at the generated assembly.
Another source of performance penalty might come from the fact that we are row-major. The original Fortran code is column-major which fits better the algorithm that works with columns and so the memory access pattern is more cache friendly.