gonum.org/v1/gonum@v0.14.0/mat/lq_test.go (about)

     1  // Copyright ©2013 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package mat
     6  
     7  import (
     8  	"testing"
     9  
    10  	"golang.org/x/exp/rand"
    11  )
    12  
    13  func TestLQ(t *testing.T) {
    14  	t.Parallel()
    15  	rnd := rand.New(rand.NewSource(1))
    16  	for _, test := range []struct {
    17  		m, n int
    18  	}{
    19  		{5, 5},
    20  		{5, 10},
    21  	} {
    22  		m := test.m
    23  		n := test.n
    24  		a := NewDense(m, n, nil)
    25  		for i := 0; i < m; i++ {
    26  			for j := 0; j < n; j++ {
    27  				a.Set(i, j, rnd.NormFloat64())
    28  			}
    29  		}
    30  		var want Dense
    31  		want.CloneFrom(a)
    32  
    33  		var lq LQ
    34  		lq.Factorize(a)
    35  		var l, q Dense
    36  		lq.QTo(&q)
    37  
    38  		if !isOrthonormal(&q, 1e-10) {
    39  			t.Errorf("Q is not orthonormal: m = %v, n = %v", m, n)
    40  		}
    41  
    42  		lq.LTo(&l)
    43  
    44  		var got Dense
    45  		got.Mul(&l, &q)
    46  		if !EqualApprox(&got, &want, 1e-12) {
    47  			t.Errorf("LQ does not equal original matrix. \nWant: %v\nGot: %v", want, got)
    48  		}
    49  	}
    50  }
    51  
    52  func TestLQSolveTo(t *testing.T) {
    53  	t.Parallel()
    54  	rnd := rand.New(rand.NewSource(1))
    55  	for _, trans := range []bool{false, true} {
    56  		for _, test := range []struct {
    57  			m, n, bc int
    58  		}{
    59  			{5, 5, 1},
    60  			{5, 10, 1},
    61  			{5, 5, 3},
    62  			{5, 10, 3},
    63  		} {
    64  			m := test.m
    65  			n := test.n
    66  			bc := test.bc
    67  			a := NewDense(m, n, nil)
    68  			for i := 0; i < m; i++ {
    69  				for j := 0; j < n; j++ {
    70  					a.Set(i, j, rnd.Float64())
    71  				}
    72  			}
    73  			br := m
    74  			if trans {
    75  				br = n
    76  			}
    77  			b := NewDense(br, bc, nil)
    78  			for i := 0; i < br; i++ {
    79  				for j := 0; j < bc; j++ {
    80  					b.Set(i, j, rnd.Float64())
    81  				}
    82  			}
    83  			var x Dense
    84  			lq := &LQ{}
    85  			lq.Factorize(a)
    86  			err := lq.SolveTo(&x, trans, b)
    87  			if err != nil {
    88  				t.Errorf("unexpected error from LQ solve: %v", err)
    89  			}
    90  
    91  			// Test that the normal equations hold.
    92  			// Aᵀ * A * x = Aᵀ * b if !trans
    93  			// A * Aᵀ * x = A * b if trans
    94  			var lhs Dense
    95  			var rhs Dense
    96  			if trans {
    97  				var tmp Dense
    98  				tmp.Mul(a, a.T())
    99  				lhs.Mul(&tmp, &x)
   100  				rhs.Mul(a, b)
   101  			} else {
   102  				var tmp Dense
   103  				tmp.Mul(a.T(), a)
   104  				lhs.Mul(&tmp, &x)
   105  				rhs.Mul(a.T(), b)
   106  			}
   107  			if !EqualApprox(&lhs, &rhs, 1e-10) {
   108  				t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs)
   109  			}
   110  		}
   111  	}
   112  	// TODO(btracey): Add in testOneInput when it exists.
   113  }
   114  
   115  func TestLQSolveToVec(t *testing.T) {
   116  	t.Parallel()
   117  	rnd := rand.New(rand.NewSource(1))
   118  	for _, trans := range []bool{false, true} {
   119  		for _, test := range []struct {
   120  			m, n int
   121  		}{
   122  			{5, 5},
   123  			{5, 10},
   124  		} {
   125  			m := test.m
   126  			n := test.n
   127  			a := NewDense(m, n, nil)
   128  			for i := 0; i < m; i++ {
   129  				for j := 0; j < n; j++ {
   130  					a.Set(i, j, rnd.Float64())
   131  				}
   132  			}
   133  			br := m
   134  			if trans {
   135  				br = n
   136  			}
   137  			b := NewVecDense(br, nil)
   138  			for i := 0; i < br; i++ {
   139  				b.SetVec(i, rnd.Float64())
   140  			}
   141  			var x VecDense
   142  			lq := &LQ{}
   143  			lq.Factorize(a)
   144  			err := lq.SolveVecTo(&x, trans, b)
   145  			if err != nil {
   146  				t.Errorf("unexpected error from LQ solve: %v", err)
   147  			}
   148  
   149  			// Test that the normal equations hold.
   150  			// Aᵀ * A * x = Aᵀ * b if !trans
   151  			// A * Aᵀ * x = A * b if trans
   152  			var lhs Dense
   153  			var rhs Dense
   154  			if trans {
   155  				var tmp Dense
   156  				tmp.Mul(a, a.T())
   157  				lhs.Mul(&tmp, &x)
   158  				rhs.Mul(a, b)
   159  			} else {
   160  				var tmp Dense
   161  				tmp.Mul(a.T(), a)
   162  				lhs.Mul(&tmp, &x)
   163  				rhs.Mul(a.T(), b)
   164  			}
   165  			if !EqualApprox(&lhs, &rhs, 1e-10) {
   166  				t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs)
   167  			}
   168  		}
   169  	}
   170  	// TODO(btracey): Add in testOneInput when it exists.
   171  }
   172  
   173  func TestLQSolveToCond(t *testing.T) {
   174  	t.Parallel()
   175  	for _, test := range []*Dense{
   176  		NewDense(2, 2, []float64{1, 0, 0, 1e-20}),
   177  		NewDense(2, 3, []float64{1, 0, 0, 0, 1e-20, 0}),
   178  	} {
   179  		m, _ := test.Dims()
   180  		var lq LQ
   181  		lq.Factorize(test)
   182  		b := NewDense(m, 2, nil)
   183  		var x Dense
   184  		if err := lq.SolveTo(&x, false, b); err == nil {
   185  			t.Error("No error for near-singular matrix in matrix solve.")
   186  		}
   187  
   188  		bvec := NewVecDense(m, nil)
   189  		var xvec VecDense
   190  		if err := lq.SolveVecTo(&xvec, false, bvec); err == nil {
   191  			t.Error("No error for near-singular matrix in matrix solve.")
   192  		}
   193  	}
   194  }