// replaces x with Q.x func (f LQFactor) applyQTo(x *Dense, trans bool) { nh, nc := f.LQ.Dims() m, n := x.Dims() if m != nc { panic(ErrShape) } proj := make([]float64, n) if trans { for k := nh - 1; k >= 0; k-- { hh := f.LQ.RawRowView(k)[k:] sub := x.View(k, 0, m-k, n).(*Dense) blas64.Gemv(blas.Trans, 1, sub.mat, blas64.Vector{Inc: 1, Data: hh}, 0, blas64.Vector{Inc: 1, Data: proj}, ) for i := k; i < m; i++ { row := x.RawRowView(i) blas64.Axpy(n, -hh[i-k], blas64.Vector{Inc: 1, Data: proj}, blas64.Vector{Inc: 1, Data: row}, ) } } } else { for k := 0; k < nh; k++ { hh := f.LQ.RawRowView(k)[k:] sub := x.View(k, 0, m-k, n).(*Dense) blas64.Gemv(blas.Trans, 1, sub.mat, blas64.Vector{Inc: 1, Data: hh}, 0, blas64.Vector{Inc: 1, Data: proj}, ) for i := k; i < m; i++ { row := x.RawRowView(i) blas64.Axpy(n, -hh[i-k], blas64.Vector{Inc: 1, Data: proj}, blas64.Vector{Inc: 1, Data: row}, ) } } } }
// LQ computes an LQ Decomposition for an m-by-n matrix a with m <= n by Householder // reflections. The LQ decomposition is an m-by-n orthogonal matrix q and an m-by-m // lower triangular matrix l so that a = l.q. LQ will panic with ErrShape if m > n. // // The LQ decomposition always exists, even if the matrix does not have full rank, // so LQ will never fail unless m > n. The primary use of the LQ decomposition is // in the least squares solution of non-square systems of simultaneous linear equations. // This will fail if LQIsFullRank() returns false. The matrix a is overwritten by the // decomposition. func LQ(a *Dense) LQFactor { // Initialize. m, n := a.Dims() if m > n { panic(ErrShape) } lq := *a lDiag := make([]float64, m) projs := NewVector(m, nil) // Main loop. for k := 0; k < m; k++ { hh := lq.RawRowView(k)[k:] norm := blas64.Nrm2(len(hh), blas64.Vector{Inc: 1, Data: hh}) lDiag[k] = norm if norm != 0 { hhNorm := (norm * math.Sqrt(1-hh[0]/norm)) if hhNorm == 0 { hh[0] = 0 } else { // Form k-th Householder vector. s := 1 / hhNorm hh[0] -= norm blas64.Scal(len(hh), s, blas64.Vector{Inc: 1, Data: hh}) // Apply transformation to remaining columns. if k < m-1 { a = lq.View(k+1, k, m-k-1, n-k).(*Dense) projs = projs.ViewVec(0, m-k-1) projs.MulVec(a, false, NewVector(len(hh), hh)) for j := 0; j < m-k-1; j++ { dst := a.RawRowView(j) blas64.Axpy(len(dst), -projs.at(j), blas64.Vector{Inc: 1, Data: hh}, blas64.Vector{Inc: 1, Data: dst}, ) } } } } } *a = lq return LQFactor{a, lDiag} }