gonum.org/v1/gonum@v0.14.0/spatial/r3/mat.go (about) 1 // Copyright ©2021 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 r3 6 7 import "gonum.org/v1/gonum/mat" 8 9 // Mat represents a 3×3 matrix. Useful for rotation matrices and such. 10 // The zero value is usable as the 3×3 zero matrix. 11 type Mat struct { 12 data *array 13 } 14 15 var _ mat.Matrix = (*Mat)(nil) 16 17 // NewMat returns a new 3×3 matrix Mat type and populates its elements 18 // with values passed as argument in row-major form. If val argument 19 // is nil then NewMat returns a matrix filled with zeros. 20 func NewMat(val []float64) *Mat { 21 if len(val) == 9 { 22 return &Mat{arrayFrom(val)} 23 } 24 if val == nil { 25 return &Mat{new(array)} 26 } 27 panic(mat.ErrShape) 28 } 29 30 // Dims returns the number of rows and columns of this matrix. 31 // This method will always return 3×3 for a Mat. 32 func (m *Mat) Dims() (r, c int) { return 3, 3 } 33 34 // T returns the transpose of Mat. Changes in the receiver will be reflected in the returned matrix. 35 func (m *Mat) T() mat.Matrix { return mat.Transpose{Matrix: m} } 36 37 // Scale multiplies the elements of a by f, placing the result in the receiver. 38 // 39 // See the mat.Scaler interface for more information. 40 func (m *Mat) Scale(f float64, a mat.Matrix) { 41 r, c := a.Dims() 42 if r != 3 || c != 3 { 43 panic(mat.ErrShape) 44 } 45 if m.data == nil { 46 m.data = new(array) 47 } 48 for i := 0; i < 3; i++ { 49 for j := 0; j < 3; j++ { 50 m.Set(i, j, f*a.At(i, j)) 51 } 52 } 53 } 54 55 // MulVec returns the matrix-vector product M⋅v. 56 func (m *Mat) MulVec(v Vec) Vec { 57 if m.data == nil { 58 return Vec{} 59 } 60 return Vec{ 61 X: v.X*m.At(0, 0) + v.Y*m.At(0, 1) + v.Z*m.At(0, 2), 62 Y: v.X*m.At(1, 0) + v.Y*m.At(1, 1) + v.Z*m.At(1, 2), 63 Z: v.X*m.At(2, 0) + v.Y*m.At(2, 1) + v.Z*m.At(2, 2), 64 } 65 } 66 67 // MulVecTrans returns the matrix-vector product Mᵀ⋅v. 68 func (m *Mat) MulVecTrans(v Vec) Vec { 69 if m.data == nil { 70 return Vec{} 71 } 72 return Vec{ 73 X: v.X*m.At(0, 0) + v.Y*m.At(1, 0) + v.Z*m.At(2, 0), 74 Y: v.X*m.At(0, 1) + v.Y*m.At(1, 1) + v.Z*m.At(2, 1), 75 Z: v.X*m.At(0, 2) + v.Y*m.At(1, 2) + v.Z*m.At(2, 2), 76 } 77 } 78 79 // CloneFrom makes a copy of a into the receiver m. 80 // Mat expects a 3×3 input matrix. 81 func (m *Mat) CloneFrom(a mat.Matrix) { 82 r, c := a.Dims() 83 if r != 3 || c != 3 { 84 panic(mat.ErrShape) 85 } 86 if m.data == nil { 87 m.data = new(array) 88 } 89 for i := 0; i < 3; i++ { 90 for j := 0; j < 3; j++ { 91 m.Set(i, j, a.At(i, j)) 92 } 93 } 94 } 95 96 // Sub subtracts the matrix b from a, placing the result in the receiver. 97 // Sub will panic if the two matrices do not have the same shape. 98 func (m *Mat) Sub(a, b mat.Matrix) { 99 if r, c := a.Dims(); r != 3 || c != 3 { 100 panic(mat.ErrShape) 101 } 102 if r, c := b.Dims(); r != 3 || c != 3 { 103 panic(mat.ErrShape) 104 } 105 if m.data == nil { 106 m.data = new(array) 107 } 108 109 m.Set(0, 0, a.At(0, 0)-b.At(0, 0)) 110 m.Set(0, 1, a.At(0, 1)-b.At(0, 1)) 111 m.Set(0, 2, a.At(0, 2)-b.At(0, 2)) 112 m.Set(1, 0, a.At(1, 0)-b.At(1, 0)) 113 m.Set(1, 1, a.At(1, 1)-b.At(1, 1)) 114 m.Set(1, 2, a.At(1, 2)-b.At(1, 2)) 115 m.Set(2, 0, a.At(2, 0)-b.At(2, 0)) 116 m.Set(2, 1, a.At(2, 1)-b.At(2, 1)) 117 m.Set(2, 2, a.At(2, 2)-b.At(2, 2)) 118 } 119 120 // Add adds a and b element-wise, placing the result in the receiver. Add will panic if the two matrices do not have the same shape. 121 func (m *Mat) Add(a, b mat.Matrix) { 122 if r, c := a.Dims(); r != 3 || c != 3 { 123 panic(mat.ErrShape) 124 } 125 if r, c := b.Dims(); r != 3 || c != 3 { 126 panic(mat.ErrShape) 127 } 128 if m.data == nil { 129 m.data = new(array) 130 } 131 132 m.Set(0, 0, a.At(0, 0)+b.At(0, 0)) 133 m.Set(0, 1, a.At(0, 1)+b.At(0, 1)) 134 m.Set(0, 2, a.At(0, 2)+b.At(0, 2)) 135 m.Set(1, 0, a.At(1, 0)+b.At(1, 0)) 136 m.Set(1, 1, a.At(1, 1)+b.At(1, 1)) 137 m.Set(1, 2, a.At(1, 2)+b.At(1, 2)) 138 m.Set(2, 0, a.At(2, 0)+b.At(2, 0)) 139 m.Set(2, 1, a.At(2, 1)+b.At(2, 1)) 140 m.Set(2, 2, a.At(2, 2)+b.At(2, 2)) 141 } 142 143 // VecRow returns the elements in the ith row of the receiver. 144 func (m *Mat) VecRow(i int) Vec { 145 if i > 2 { 146 panic(mat.ErrRowAccess) 147 } 148 if m.data == nil { 149 return Vec{} 150 } 151 return Vec{X: m.At(i, 0), Y: m.At(i, 1), Z: m.At(i, 2)} 152 } 153 154 // VecCol returns the elements in the jth column of the receiver. 155 func (m *Mat) VecCol(j int) Vec { 156 if j > 2 { 157 panic(mat.ErrColAccess) 158 } 159 if m.data == nil { 160 return Vec{} 161 } 162 return Vec{X: m.At(0, j), Y: m.At(1, j), Z: m.At(2, j)} 163 } 164 165 // Outer calculates the outer product of the vectors x and y, 166 // where x and y are treated as column vectors, and stores the result in the receiver. 167 // 168 // m = alpha * x * yᵀ 169 func (m *Mat) Outer(alpha float64, x, y Vec) { 170 ax := alpha * x.X 171 ay := alpha * x.Y 172 az := alpha * x.Z 173 m.Set(0, 0, ax*y.X) 174 m.Set(0, 1, ax*y.Y) 175 m.Set(0, 2, ax*y.Z) 176 177 m.Set(1, 0, ay*y.X) 178 m.Set(1, 1, ay*y.Y) 179 m.Set(1, 2, ay*y.Z) 180 181 m.Set(2, 0, az*y.X) 182 m.Set(2, 1, az*y.Y) 183 m.Set(2, 2, az*y.Z) 184 } 185 186 // Det calculates the determinant of the receiver using the following formula 187 // 188 // ⎡a b c⎤ 189 // m = ⎢d e f⎥ 190 // ⎣g h i⎦ 191 // det(m) = a(ei − fh) − b(di − fg) + c(dh − eg) 192 func (m *Mat) Det() float64 { 193 a := m.At(0, 0) 194 b := m.At(0, 1) 195 c := m.At(0, 2) 196 197 deta := m.At(1, 1)*m.At(2, 2) - m.At(1, 2)*m.At(2, 1) 198 detb := m.At(1, 0)*m.At(2, 2) - m.At(1, 2)*m.At(2, 0) 199 detc := m.At(1, 0)*m.At(2, 1) - m.At(1, 1)*m.At(2, 0) 200 return a*deta - b*detb + c*detc 201 } 202 203 // Skew sets the receiver to the 3×3 skew symmetric matrix 204 // (right hand system) of v. 205 // 206 // ⎡ 0 -z y⎤ 207 // Skew({x,y,z}) = ⎢ z 0 -x⎥ 208 // ⎣-y x 0⎦ 209 func (m *Mat) Skew(v Vec) { 210 m.Set(0, 0, 0) 211 m.Set(0, 1, -v.Z) 212 m.Set(0, 2, v.Y) 213 m.Set(1, 0, v.Z) 214 m.Set(1, 1, 0) 215 m.Set(1, 2, -v.X) 216 m.Set(2, 0, -v.Y) 217 m.Set(2, 1, v.X) 218 m.Set(2, 2, 0) 219 } 220 221 // Hessian sets the receiver to the Hessian matrix of the scalar field at the point p, 222 // approximated using finite differences with the given step sizes. 223 // The field is evaluated at points in the area surrounding p by adding 224 // at most 2 components of step to p. Hessian expects the field's second partial 225 // derivatives are all continuous for correct results. 226 func (m *Mat) Hessian(p, step Vec, field func(Vec) float64) { 227 dx := Vec{X: step.X} 228 dy := Vec{Y: step.Y} 229 dz := Vec{Z: step.Z} 230 fp := field(p) 231 fxp := field(Add(p, dx)) 232 fxm := field(Sub(p, dx)) 233 fxx := (fxp - 2*fp + fxm) / (step.X * step.X) 234 235 fyp := field(Add(p, dy)) 236 fym := field(Sub(p, dy)) 237 fyy := (fyp - 2*fp + fym) / (step.Y * step.Y) 238 239 aux := Add(dx, dy) 240 fxyp := field(Add(p, aux)) 241 fxym := field(Sub(p, aux)) 242 fxy := (fxyp - fxp - fyp + 2*fp - fxm - fym + fxym) / (2 * step.X * step.Y) 243 244 fzp := field(Add(p, dz)) 245 fzm := field(Sub(p, dz)) 246 fzz := (fzp - 2*fp + fzm) / (step.Z * step.Z) 247 248 aux = Add(dx, dz) 249 fxzp := field(Add(p, aux)) 250 fxzm := field(Sub(p, aux)) 251 fxz := (fxzp - fxp - fzp + 2*fp - fxm - fzm + fxzm) / (2 * step.X * step.Z) 252 253 aux = Add(dy, dz) 254 fyzp := field(Add(p, aux)) 255 fyzm := field(Sub(p, aux)) 256 fyz := (fyzp - fyp - fzp + 2*fp - fym - fzm + fyzm) / (2 * step.Y * step.Z) 257 258 m.Set(0, 0, fxx) 259 m.Set(0, 1, fxy) 260 m.Set(0, 2, fxz) 261 262 m.Set(1, 0, fxy) 263 m.Set(1, 1, fyy) 264 m.Set(1, 2, fyz) 265 266 m.Set(2, 0, fxz) 267 m.Set(2, 1, fyz) 268 m.Set(2, 2, fzz) 269 } 270 271 // Jacobian sets the receiver to the Jacobian matrix of the vector field at 272 // the point p, approximated using finite differences with the given step sizes. 273 // 274 // The Jacobian matrix J is the matrix of all first-order partial derivatives of f. 275 // If f maps an 3-dimensional vector x to an 3-dimensional vector y = f(x), J is 276 // a 3×3 matrix whose elements are given as 277 // 278 // J_{i,j} = ∂f_i/∂x_j, 279 // 280 // or expanded out 281 // 282 // [ ∂f_1/∂x_1 ∂f_1/∂x_2 ∂f_1/∂x_3 ] 283 // J = [ ∂f_2/∂x_1 ∂f_2/∂x_2 ∂f_2/∂x_3 ] 284 // [ ∂f_3/∂x_1 ∂f_3/∂x_2 ∂f_3/∂x_3 ] 285 // 286 // Jacobian expects the field's first order partial derivatives are all 287 // continuous for correct results. 288 func (m *Mat) Jacobian(p, step Vec, field func(Vec) Vec) { 289 dx := Vec{X: step.X} 290 dy := Vec{Y: step.Y} 291 dz := Vec{Z: step.Z} 292 293 dfdx := Scale(0.5/step.X, Sub(field(Add(p, dx)), field(Sub(p, dx)))) 294 dfdy := Scale(0.5/step.Y, Sub(field(Add(p, dy)), field(Sub(p, dy)))) 295 dfdz := Scale(0.5/step.Z, Sub(field(Add(p, dz)), field(Sub(p, dz)))) 296 m.Set(0, 0, dfdx.X) 297 m.Set(0, 1, dfdy.X) 298 m.Set(0, 2, dfdz.X) 299 300 m.Set(1, 0, dfdx.Y) 301 m.Set(1, 1, dfdy.Y) 302 m.Set(1, 2, dfdz.Y) 303 304 m.Set(2, 0, dfdx.Z) 305 m.Set(2, 1, dfdy.Z) 306 m.Set(2, 2, dfdz.Z) 307 }