// S returns the diagonal matrix of singular values func (s svd) S() (S mesh.Mesher) { if s.m < s.n { S = mesh.Gen(nil, s.m, s.n) } else { S = mesh.Gen(nil, s.n, s.n) } for i := 0; i < int(math.Min(float64(s.m), float64(s.n))); i++ { S.SetAtNode(s.s[i], i, i) } return }
// U returns the left singular values func (s svd) U() (U mesh.Mesher) { if s.m < s.n { U = mesh.Gen(nil, s.m, s.m) for i := 0; i < s.m; i++ { for j := 0; j < s.m; j++ { U.SetAtNode(s.u[i*s.n+j], i, j) } } } else { U = mesh.Gen(nil, s.m, s.n) copy(U.Vec().Slice(), s.u) } return }
func main() { _ = mesh.Gen(vec.New( 0.235918, 0.667775, 0.793897, 0.631316, 0.943595, 0.0163339, 0.31451, 0.943855, 0.838414, 0.938603, 0.806399, 0.995342, 0.79334, 0.505524, 0.735964, 0.19605, 0.494912, 0.184079, 0.957973, 0.700138, 0.21507, 0.581624, 0.799555, 0.779833, 0.696537, 0.373588, 0.534098, 0.348679, 0.490353, 0.333384, 0.948874, 0.153949, 0.703542, 0.59173, 0.77532, 0.721638, ), 6, 6) a := mesh.Gen(vec.New( 0.2417, 0.5752, 0.0430, 0.5470, 0.3685, 0.4868, 0.8176, 0.4039, 0.0598, 0.1690, 0.2963, 0.6256, 0.4359, 0.7948, 0.0965, 0.2348, 0.6491, 0.7447, 0.7802, 0.4468, 0.6443, 0.1320, 0.3532, 0.7317, 0.1890, 0.0811, 0.3063, 0.3786, 0.9421, 0.8212, 0.6477, 0.6868, 0.9294, 0.5085, 0.8116, 0.9561, 0.0154, 0.4509, 0.1835, 0.7757, 0.5108, 0.5328, ), 6, 7) var s SVDer st := time.Now() for j := 0; j < 1e3; j++ { s = mesh.SVD(a) } fmt.Println("Since: ", time.Since(st)/1e3) fmt.Println("U: ", s.U()) // 6x6 fmt.Println("S: ", s.S()) // 6x7 fmt.Println("V: ", s.V()) // 7x7 us := mesh.Gen(nil, 6, 7) us.Mul(s.U(), s.S()) usv := mesh.Gen(nil, 6, 7) vt := mesh.Gen(nil, 7, 7) vt.T(s.V()) usv.Mul(us, vt) fmt.Println("usv: ", usv) fmt.Println("cond: ", s.Cond()) }
// SVD computes the singular value decomposition of an // mxn matrix A with m >= n. // SVD is an mxn orthogonal matrix U // nxn diagonal matrix S // nxn orthogonal matrix V so that A = U*S*V' // Singualar Values are ordered so that // sigma[0] >= sigma[1] >= ... >= sigma[n-1] // Singualr value decomposition always exists // and will therefore never fail. // The matrix condition number & effective numerical // rank can be computed from this decomposition func SVD(a mesh.Mesher) SVDer { var sqa mesh.Mesher svd := new(svd) m, n, _ := a.Size() svd.m, svd.n = m, n if m < n { // 6x7 // we will make it square by appending // a zero column sqa = mesh.Gen(nil, n, n) // 7x7 m = n // svd.m = m } else if m >= n { // 7x6 sqa = mesh.Gen(nil, m, m) // 7x7 n = m // svd.n = n } sqa.Clone(a) svd.u = make([]float64, m*n) // 7x7 nu := n svd.s = make([]float64, n) // 7x7 svd.v = make([]float64, n*n) // 7x7 e := make([]float64, n) // 7 work := make([]float64, m) // 7 wantu, wantv := true, true // reduce A to bidiagonal form, storing the diagonal // elements in s and the super-diagonal elements in e nct := int(math.Min(float64(m-1), float64(n))) // 6 = min(6, 7) nrt := int(math.Max(0, math.Min(float64(n-2), float64(m)))) // 5 = max(0, min(5, 7)) for k := 0; k < int(math.Max(float64(nct), float64(nrt))); k++ { if k < nct { // compute the transformation for the kth column and place // the kth diagonal in s[k] // compute 2-norm of k-th column without under/overflow svd.s[k] = 0 for i := k; i < m; i++ { svd.s[k] = math.Hypot(svd.s[k], sqa.GetAtNode(i, k)) } if svd.s[k] != 0.0 { if sqa.GetAtNode(k, k) < 0.0 { svd.s[k] = -svd.s[k] } for i := k; i < m; i++ { sqa.SetAtNode(sqa.GetAtNode(i, k)/svd.s[k], i, k) } sqa.SetAtNode(sqa.GetAtNode(k, k)+1.0, k, k) } svd.s[k] = -svd.s[k] } for j := k + 1; j < n; j++ { if k < nct && svd.s[k] != 0 { // apply the transformation t := 0.0 for i := k; i < m; i++ { t += sqa.GetAtNode(i, k) * sqa.GetAtNode(i, j) } t /= -sqa.GetAtNode(k, k) for i := k; i < m; i++ { sqa.SetAtNode(sqa.GetAtNode(i, j)+t*sqa.GetAtNode(i, k), i, j) } } // place the kth row of A into e for the subsequent calculation of // the row transformation e[j] = sqa.GetAtNode(k, j) } if wantu && (k < nct) { // place the transformation in U for subsequent back multiplication for i := k; i < m; i++ { svd.u[i*n+k] = sqa.GetAtNode(i, k) } } if k < nrt { // compute the kth row transformation and place the // kth superdiagonal in e[k] // compute the 2-norm without under/overflow e[k] = 0 for i := k + 1; i < n; i++ { e[k] = math.Hypot(e[k], e[i]) } if e[k] != 0.0 { if e[k+1] < 0.0 { e[k] = -e[k] } for i := k + 1; i < n; i++ { e[i] /= e[k] } e[k+1] += 1.0 } e[k] = -e[k] if (k+1 < m) && (e[k] != 0.0) { // apply the transformation for i := k + 1; i < m; i++ { work[i] = 0.0 } for j := k + 1; j < n; j++ { for i := k + 1; i < m; i++ { work[i] += e[j] * sqa.GetAtNode(i, j) } } for j := k + 1; j < n; j++ { t := -e[j] / e[k+1] for i := k + 1; i < m; i++ { sqa.SetAtNode(sqa.GetAtNode(i, j)+t*work[i], i, j) } } } if wantv { // place the transformation in V for subsequent back // multiplication for i := k + 1; i < n; i++ { svd.v[i*n+k] = e[i] } } } } // set up the final bidiagonal matrix of order p p := int(math.Min(float64(n), float64(m+1))) if nct < n { svd.s[nct] = sqa.GetAtNode(nct, nct) } if m < p { svd.s[p-1] = 0.0 } if nrt+1 < p { e[nrt] = sqa.GetAtNode(nrt, p-1) } e[p-1] = 0.0 // if required generate U if wantu { for j := nct; j < nu; j++ { for i := 0; i < m; i++ { svd.u[i*n+j] = 0.0 } svd.u[j*n+j] = 1.0 } for k := nct - 1; k >= 0; k-- { if svd.s[k] != 0 { for j := k + 1; j < nu; j++ { t := 0.0 for i := k; i < m; i++ { t += svd.u[i*n+k] * svd.u[i*n+j] } t /= -svd.u[k*n+k] for i := k; i < m; i++ { svd.u[i*n+j] += t * svd.u[i*n+k] } } for i := k; i < m; i++ { svd.u[i*n+k] = -svd.u[i*n+k] } svd.u[k*n+k] += 1.0 for i := 0; i < k-1; i++ { svd.u[i*n+k] = 0.0 } } else { for i := 0; i < m; i++ { svd.u[i*n+k] = 0.0 } svd.u[k*n+k] = 1.0 } } } // if required, generate v if wantv { for k := n - 1; k >= 0; k-- { if k < nrt && e[k] != 0.0 { for j := k + 1; j < nu; j++ { t := 0.0 for i := k + 1; i < n; i++ { t += svd.v[i*n+k] * svd.v[i*n+j] } t /= -svd.v[(k+1)*n+k] for i := k + 1; i < n; i++ { svd.v[i*n+j] += t * svd.v[i*n+k] } } } for i := 0; i < n; i++ { svd.v[i*n+k] = 0.0 } svd.v[k*n+k] = 1.0 } } // main iteration loop for the singualr values pp := p - 1 iter := 0 eps := math.Pow(2.0, -52.0) for p > 0 { k, kase := 0, 0 // here is where a test for too many iterations would go // // this section of the program inspects for negligible // elements in the s and e arrays. On completion the // variables kase and k are set as follows, // kase = 1 if s(p) && e[k-1] are negligible && k<p // kase = 2 if s(k) is negligible && k < p // kase = 3 if e[k-1] is negligible, k<p, and // s(k), ..., s(p) are not negligible (qr step). // kase = 4 if e(p-1) is negligible (convergence). for k = p - 2; k >= -1; k-- { if k == -1 { break } if math.Abs(e[k]) <= eps*(math.Abs(svd.s[k])+math.Abs(svd.s[k+1])) { e[k] = 0.0 break } } if k == p-2 { kase = 4 } else { ks := 0 for ks = p - 1; ks >= k; ks-- { if ks == k { break } t := 0.0 if ks != p { t = math.Abs(e[ks]) } if ks != k+1 { t += math.Abs(e[ks-1]) } else { t += 0.0 } if math.Abs(svd.s[ks]) <= eps*t { svd.s[ks] = 0.0 break } } if ks == k { kase = 3 } else if ks == p-1 { kase = 1 } else { kase = 2 k = ks } } k++ // perform the task indicated by kase switch kase { case 1: { // deflate negligible s[p] f := e[p-2] e[p-2] = 0.0 for j := p - 2; j >= k; j-- { t := math.Hypot(svd.s[j], f) cs := svd.s[j] / t sn := f / t svd.s[j] = t if j != k { f = -sn * e[j-1] e[j-1] *= cs } if wantv { for i := 0; i < n; i++ { t = cs*svd.v[i*n+j] + sn*svd.v[i*n+(p-1)] svd.v[i*n+(p-1)] = cs*svd.v[i*n+(p-1)] - sn*svd.v[i*n+j] svd.v[i*n+j] = t } } } } case 2: { // split at negligible s[k] f := e[k-1] e[k-1] = 0.0 for j := k; j < p; j++ { t := math.Hypot(svd.s[j], f) cs := svd.s[j] / t sn := f / t svd.s[j] = t f = -sn * e[j] e[j] *= cs if wantu { for i := 0; i < m; i++ { t = cs*svd.u[i*n+j] + sn*svd.u[i*n+(k-1)] svd.u[i*n+(k-1)] = -sn*svd.u[i*n+j] + cs*svd.u[i*n+(k-1)] svd.u[i*n+j] = t } } } } case 3: { // perform one qr step // // calculate the shift scale := math.Max(math.Max(math.Max(math.Max( math.Abs(svd.s[p-1]), math.Abs(svd.s[p-2])), math.Abs(e[p-2])), math.Abs(svd.s[k])), math.Abs(e[k])) sp := svd.s[p-1] / scale spm1 := svd.s[p-2] / scale epm1 := e[p-2] / scale sk := svd.s[k] / scale ek := e[k] / scale b := ((spm1+sp)*(spm1-sp) + epm1*epm1) / 2.0 c := (sp * epm1) * (sp * epm1) shift := 0.0 if b != 0.0 || c != 0.0 { shift = math.Sqrt(b*b + c) if b < 0.0 { shift = -shift } shift = c / (b + shift) } f := (sk+sp)*(sk-sp) + shift g := sk * ek // chase zeros for j := k; j < p-1; j++ { t := math.Hypot(f, g) cs := f / t sn := g / t if j != k { e[j-1] = t } f = cs*svd.s[j] + sn*e[j] e[j] = cs*e[j] - sn*svd.s[j] g = sn * svd.s[j+1] svd.s[j+1] *= cs if wantv { for i := 0; i < n; i++ { t = cs*svd.v[i*n+j] + sn*svd.v[i*n+(j+1)] svd.v[i*n+(j+1)] = -sn*svd.v[i*n+j] + cs*svd.v[i*n+(j+1)] svd.v[i*n+j] = t } } t = math.Hypot(f, g) cs = f / t sn = g / t svd.s[j] = t f = cs*e[j] + sn*svd.s[j+1] svd.s[j+1] = -sn*e[j] + cs*svd.s[j+1] g = sn * e[j+1] e[j+1] = cs * e[j+1] if wantu && j < m-1 { for i := 0; i < m; i++ { t = cs*svd.u[i*n+j] + sn*svd.u[i*n+(j+1)] svd.u[i*n+(j+1)] = -sn*svd.u[i*n+j] + cs*svd.u[i*n+(j+1)] svd.u[i*n+j] = t } } } e[p-2] = f iter++ } case 4: { // TODO implementation // // make the singular values positive if svd.s[k] <= 0 { if svd.s[k] < 0 { svd.s[k] = -svd.s[k] } else { svd.s[k] = 0 } if wantv { for i := 0; i <= pp; i++ { svd.v[i*n+k] = -svd.v[i*n+k] } } } // order the singular values for k < pp { if svd.s[k] >= svd.s[k+1] { break } t := svd.s[k] svd.s[k] = svd.s[k+1] svd.s[k+1] = t if wantv && k < n-1 { for i := 0; i < n; i++ { t = svd.v[i*n+(k+1)] svd.v[i*n+(k+1)] = svd.v[i*n+k] svd.v[i*n+k] = t } } if wantu && k < m-1 { for i := 0; i < m; i++ { t = svd.u[i*n+(k+1)] svd.u[i*n+(k+1)] = svd.u[i*n+k] svd.u[i*n+k] = t } } k++ } iter = 0 p-- } } } return svd }
// V returns the right singular values func (s svd) V() (V mesh.Mesher) { V = mesh.Gen(nil, s.n, s.n) copy(V.Vec().Slice(), s.v) return }