Ejemplo n.º 1
0
// 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
}
Ejemplo n.º 2
0
// 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
}
Ejemplo n.º 3
0
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())
}
Ejemplo n.º 4
0
// 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
}
Ejemplo n.º 5
0
// 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
}