gonum.org/v1/gonum@v0.15.1-0.20240517103525-f853624cb1bb/mat/solve.go (about) 1 // Copyright ©2015 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 // Solve solves the linear least squares problem 8 // 9 // minimize over x |b - A*x|_2 10 // 11 // where A is an m×n matrix, b is a given m element vector and x is n element 12 // solution vector. Solve assumes that A has full rank, that is 13 // 14 // rank(A) = min(m,n) 15 // 16 // If m >= n, Solve finds the unique least squares solution of an overdetermined 17 // system. 18 // 19 // If m < n, there is an infinite number of solutions that satisfy b-A*x=0. In 20 // this case Solve finds the unique solution of an underdetermined system that 21 // minimizes |x|_2. 22 // 23 // Several right-hand side vectors b and solution vectors x can be handled in a 24 // single call. Vectors b are stored in the columns of the m×k matrix B. Vectors 25 // x will be stored in-place into the n×k receiver. 26 // 27 // If the underlying matrix of a is a SolveToer, its SolveTo method is used, 28 // otherwise a Dense copy of a will be used for the solution. 29 // 30 // If A does not have full rank, a Condition error is returned. See the 31 // documentation for Condition for more information. 32 func (m *Dense) Solve(a, b Matrix) error { 33 aU, aTrans := untransposeExtract(a) 34 if a, ok := aU.(SolveToer); ok { 35 return a.SolveTo(m, aTrans, b) 36 } 37 38 ar, ac := a.Dims() 39 br, bc := b.Dims() 40 if ar != br { 41 panic(ErrShape) 42 } 43 m.reuseAsNonZeroed(ac, bc) 44 45 switch { 46 case ar == ac: 47 if a == b { 48 // x = I. 49 if ar == 1 { 50 m.mat.Data[0] = 1 51 return nil 52 } 53 for i := 0; i < ar; i++ { 54 v := m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+ac] 55 zero(v) 56 v[i] = 1 57 } 58 return nil 59 } 60 var lu LU 61 lu.Factorize(a) 62 return lu.SolveTo(m, false, b) 63 case ar > ac: 64 var qr QR 65 qr.Factorize(a) 66 return qr.SolveTo(m, false, b) 67 default: 68 var lq LQ 69 lq.Factorize(a) 70 return lq.SolveTo(m, false, b) 71 } 72 } 73 74 // SolveVec solves the linear least squares problem 75 // 76 // minimize over x |b - A*x|_2 77 // 78 // where A is an m×n matrix, b is a given m element vector and x is n element 79 // solution vector. Solve assumes that A has full rank, that is 80 // 81 // rank(A) = min(m,n) 82 // 83 // If m >= n, Solve finds the unique least squares solution of an overdetermined 84 // system. 85 // 86 // If m < n, there is an infinite number of solutions that satisfy b-A*x=0. In 87 // this case Solve finds the unique solution of an underdetermined system that 88 // minimizes |x|_2. 89 // 90 // The solution vector x will be stored in-place into the receiver. 91 // 92 // If A does not have full rank, a Condition error is returned. See the 93 // documentation for Condition for more information. 94 func (v *VecDense) SolveVec(a Matrix, b Vector) error { 95 if _, bc := b.Dims(); bc != 1 { 96 panic(ErrShape) 97 } 98 _, c := a.Dims() 99 100 // The Solve implementation is non-trivial, so rather than duplicate the code, 101 // instead recast the VecDenses as Dense and call the matrix code. 102 103 if rv, ok := b.(RawVectorer); ok { 104 bmat := rv.RawVector() 105 if v != b { 106 v.checkOverlap(bmat) 107 } 108 v.reuseAsNonZeroed(c) 109 m := v.asDense() 110 // We conditionally create bm as m when b and v are identical 111 // to prevent the overlap detection code from identifying m 112 // and bm as overlapping but not identical. 113 bm := m 114 if v != b { 115 b := VecDense{mat: bmat} 116 bm = b.asDense() 117 } 118 return m.Solve(a, bm) 119 } 120 121 v.reuseAsNonZeroed(c) 122 m := v.asDense() 123 return m.Solve(a, b) 124 }