func DpotrfTest(t *testing.T, impl Dpotrfer) { bi := blas64.Implementation() for i, test := range []struct { n int }{ {n: 10}, {n: 30}, {n: 63}, {n: 65}, {n: 128}, {n: 1000}, } { n := test.n // Construct a positive-definite symmetric matrix base := make([]float64, n*n) for i := range base { base[i] = rand.Float64() } a := make([]float64, len(base)) bi.Dgemm(blas.Trans, blas.NoTrans, n, n, n, 1, base, n, base, n, 0, a, n) aCopy := make([]float64, len(a)) copy(aCopy, a) // Test with Upper impl.Dpotrf(blas.Upper, n, a, n) // zero all the other elements for i := 0; i < n; i++ { for j := 0; j < i; j++ { a[i*n+j] = 0 } } // Multiply u^T * u ans := make([]float64, len(a)) bi.Dsyrk(blas.Upper, blas.Trans, n, n, 1, a, n, 0, ans, n) match := true for i := 0; i < n; i++ { for j := i; j < n; j++ { if !floats.EqualWithinAbsOrRel(ans[i*n+j], aCopy[i*n+j], 1e-14, 1e-14) { match = false } } } if !match { //fmt.Println(aCopy) //fmt.Println(ans) t.Errorf("Case %v: Mismatch for upper", i) } } }
// Dpotrf computes the cholesky decomposition of the symmetric positive definite // matrix a. If ul == blas.Upper, then a is stored as an upper-triangular matrix, // and a = U^T U is stored in place into a. If ul == blas.Lower, then a = L L^T // is computed and stored in-place into a. If a is not positive definite, false // is returned. This is the unblocked version of the algorithm. func (Implementation) Dpotf2(ul blas.Uplo, n int, a []float64, lda int) (ok bool) { if ul != blas.Upper && ul != blas.Lower { panic(badUplo) } if n < 0 { panic(nLT0) } if lda < n { panic(badLdA) } if n == 0 { return true } bi := blas64.Implementation() if ul == blas.Upper { for j := 0; j < n; j++ { ajj := a[j*lda+j] if j != 0 { ajj -= bi.Ddot(j, a[j:], lda, a[j:], lda) } if ajj <= 0 || math.IsNaN(ajj) { a[j*lda+j] = ajj return false } ajj = math.Sqrt(ajj) a[j*lda+j] = ajj if j < n-1 { bi.Dgemv(blas.Trans, j, n-j-1, -1, a[j+1:], lda, a[j:], lda, 1, a[j*lda+j+1:], 1) bi.Dscal(n-j-1, 1/ajj, a[j*lda+j+1:], 1) } } return true } for j := 0; j < n; j++ { ajj := a[j*lda+j] if j != 0 { ajj -= bi.Ddot(j, a[j*lda:], 1, a[j*lda:], 1) } if ajj <= 0 || math.IsNaN(ajj) { a[j*lda+j] = ajj return false } ajj = math.Sqrt(ajj) a[j*lda+j] = ajj if j < n-1 { bi.Dgemv(blas.NoTrans, n-j-1, j, -1, a[(j+1)*lda:], lda, a[j*lda:], 1, 1, a[(j+1)*lda+j:], lda) bi.Dscal(n-j-1, 1/ajj, a[(j+1)*lda+j:], lda) } } return true }
// Dpotrf computes the cholesky decomposition of the symmetric positive definite // matrix a. If ul == blas.Upper, then a is stored as an upper-triangular matrix, // and a = U U^T is stored in place into a. If ul == blas.Lower, then a = L L^T // is computed and stored in-place into a. If a is not positive definite, false // is returned. This is the blocked version of the algorithm. func (impl Implementation) Dpotrf(ul blas.Uplo, n int, a []float64, lda int) (ok bool) { bi := blas64.Implementation() if ul != blas.Upper && ul != blas.Lower { panic(badUplo) } if n < 0 { panic(nLT0) } if lda < n { panic(badLdA) } if n == 0 { return true } nb := blockSize() if n <= nb { return impl.Dpotf2(ul, n, a, lda) } if ul == blas.Upper { for j := 0; j < n; j += nb { jb := min(nb, n-j) bi.Dsyrk(blas.Upper, blas.Trans, jb, j, -1, a[j:], lda, 1, a[j*lda+j:], lda) ok = impl.Dpotf2(blas.Upper, jb, a[j*lda+j:], lda) if !ok { return ok } if j+jb < n { bi.Dgemm(blas.Trans, blas.NoTrans, jb, n-j-jb, j, -1, a[j:], lda, a[j+jb:], lda, 1, a[j*lda+j+jb:], lda) bi.Dtrsm(blas.Left, blas.Upper, blas.Trans, blas.NonUnit, jb, n-j-jb, 1, a[j*lda+j:], lda, a[j*lda+j+jb:], lda) } } return true } for j := 0; j < n; j += nb { jb := min(nb, n-j) bi.Dsyrk(blas.Lower, blas.NoTrans, jb, j, -1, a[j*lda:], lda, 1, a[j*lda+j:], lda) ok := impl.Dpotf2(blas.Lower, jb, a[j*lda+j:], lda) if !ok { return ok } if j+jb < n { bi.Dgemm(blas.NoTrans, blas.Trans, n-j-jb, jb, j, -1, a[(j+jb)*lda:], lda, a[j*lda:], lda, 1, a[(j+jb)*lda+j:], lda) bi.Dtrsm(blas.Right, blas.Lower, blas.Trans, blas.NonUnit, n-j-jb, jb, 1, a[j*lda+j:], lda, a[(j+jb)*lda+j:], lda) } } return true }