Beispiel #1
0
// Norm returns the specified (induced) norm of the matrix a. See
// https://en.wikipedia.org/wiki/Matrix_norm for the definition of an induced norm.
//
// Valid norms are:
//    1 - The maximum absolute column sum
//    2 - Frobenius norm, the square root of the sum of the squares of the elements.
//  Inf - The maximum absolute row sum.
// Norm will panic with ErrNormOrder if an illegal norm order is specified and
// with matrix.ErrShape if the matrix has zero size.
func Norm(a Matrix, norm float64) float64 {
	r, c := a.Dims()
	if r == 0 || c == 0 {
		panic(matrix.ErrShape)
	}
	aU, aTrans := untranspose(a)
	var work []float64
	switch rma := aU.(type) {
	case RawMatrixer:
		rm := rma.RawMatrix()
		n := normLapack(norm, aTrans)
		if n == lapack.MaxColumnSum {
			work = make([]float64, rm.Cols)
		}
		return lapack64.Lange(n, rm, work)
	case RawTriangular:
		rm := rma.RawTriangular()
		n := normLapack(norm, aTrans)
		if n == lapack.MaxRowSum || n == lapack.MaxColumnSum {
			work = make([]float64, rm.N)
		}
		return lapack64.Lantr(n, rm, work)
	case RawSymmetricer:
		rm := rma.RawSymmetric()
		n := normLapack(norm, aTrans)
		if n == lapack.MaxRowSum || n == lapack.MaxColumnSum {
			work = make([]float64, rm.N)
		}
		return lapack64.Lansy(n, rm, work)
	case *Vector:
		rv := rma.RawVector()
		switch norm {
		default:
			panic("unreachable")
		case 1:
			if aTrans {
				imax := blas64.Iamax(rma.n, rv)
				return math.Abs(rma.At(imax, 0))
			}
			return blas64.Asum(rma.n, rv)
		case 2:
			return blas64.Nrm2(rma.n, rv)
		case math.Inf(1):
			if aTrans {
				return blas64.Asum(rma.n, rv)
			}
			imax := blas64.Iamax(rma.n, rv)
			return math.Abs(rma.At(imax, 0))
		}
	}
	switch norm {
	default:
		panic("unreachable")
	case 1:
		var max float64
		for j := 0; j < c; j++ {
			var sum float64
			for i := 0; i < r; i++ {
				sum += math.Abs(a.At(i, j))
			}
			if sum > max {
				max = sum
			}
		}
		return max
	case 2:
		var sum float64
		for i := 0; i < r; i++ {
			for j := 0; j < c; j++ {
				v := a.At(i, j)
				sum += v * v
			}
		}
		return math.Sqrt(sum)
	case math.Inf(1):
		var max float64
		for i := 0; i < r; i++ {
			var sum float64
			for j := 0; j < c; j++ {
				sum += math.Abs(a.At(i, j))
			}
			if sum > max {
				max = sum
			}
		}
		return max
	}
}
Beispiel #2
0
func DlangeTest(t *testing.T, impl Dlanger) {
	for _, test := range []struct {
		m, n, lda int
	}{
		{4, 3, 0},
		{3, 4, 0},
		{4, 3, 100},
		{3, 4, 100},
	} {
		m := test.m
		n := test.n
		lda := test.lda
		if lda == 0 {
			lda = n
		}
		a := make([]float64, m*lda)
		for i := range a {
			a[i] = (rand.Float64() - 0.5)
		}
		work := make([]float64, n)
		for i := range work {
			work[i] = rand.Float64()
		}
		aCopy := make([]float64, len(a))
		copy(aCopy, a)

		// Test MaxAbs norm.
		norm := impl.Dlange(lapack.MaxAbs, m, n, a, lda, work)
		var ans float64
		for i := 0; i < m; i++ {
			idx := blas64.Iamax(n, blas64.Vector{1, aCopy[i*lda:]})
			ans = math.Max(ans, math.Abs(a[i*lda+idx]))
		}
		// Should be strictly equal because there is no floating point summation error.
		if ans != norm {
			t.Errorf("MaxAbs mismatch. Want %v, got %v.", ans, norm)
		}

		// Test MaxColumnSum norm.
		norm = impl.Dlange(lapack.MaxColumnSum, m, n, a, lda, work)
		ans = 0
		for i := 0; i < n; i++ {
			sum := blas64.Asum(m, blas64.Vector{lda, aCopy[i:]})
			ans = math.Max(ans, sum)
		}
		if math.Abs(norm-ans) > 1e-14 {
			t.Errorf("MaxColumnSum mismatch. Want %v, got %v.", ans, norm)
		}

		// Test MaxRowSum norm.
		norm = impl.Dlange(lapack.MaxRowSum, m, n, a, lda, work)
		ans = 0
		for i := 0; i < m; i++ {
			sum := blas64.Asum(n, blas64.Vector{1, aCopy[i*lda:]})
			ans = math.Max(ans, sum)
		}
		if math.Abs(norm-ans) > 1e-14 {
			t.Errorf("MaxRowSum mismatch. Want %v, got %v.", ans, norm)
		}

		// Test Frobenius norm
		norm = impl.Dlange(lapack.NormFrob, m, n, a, lda, work)
		ans = 0
		for i := 0; i < m; i++ {
			sum := blas64.Nrm2(n, blas64.Vector{1, aCopy[i*lda:]})
			ans += sum * sum
		}
		ans = math.Sqrt(ans)
		if math.Abs(norm-ans) > 1e-14 {
			t.Errorf("NormFrob mismatch. Want %v, got %v.", ans, norm)
		}
	}
}