github.com/gopherd/gonum@v0.0.4/stat/distmat/unit_vector.go (about) 1 // Copyright ©2020 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 distmat 6 7 import ( 8 "math/rand" 9 10 "github.com/gopherd/gonum/mat" 11 "github.com/gopherd/gonum/stat/distuv" 12 ) 13 14 // UnitVector is a uniform distribution over the surface of a sphere. 15 type UnitVector struct { 16 norm distuv.Normal 17 } 18 19 // NewUnitVector constructs a unit vector generator. 20 func NewUnitVector(src rand.Source) *UnitVector { 21 return &UnitVector{norm: distuv.Normal{Mu: 0, Sigma: 1, Src: src}} 22 } 23 24 // UnitVecTo sets dst to be a random unit-length vector. 25 // 26 // This uses the algorithm of Mueller from: 27 // https://dl.acm.org/doi/10.1145/377939.377946 28 // and summarized at: 29 // https://mathworld.wolfram.com/HyperspherePointPicking.html 30 // 31 // UnitVecTo panics if dst has 0 length. 32 func (u *UnitVector) UnitVecTo(dst *mat.VecDense) { 33 r := dst.Len() 34 if r == 0 { 35 panic(zeroDim) 36 } 37 for { 38 for i := 0; i < r; i++ { 39 dst.SetVec(i, u.norm.Rand()) 40 } 41 l := mat.Norm(dst, 2) 42 // Use l only if it is not too short. Otherwise try again. 43 const minLength = 1e-5 44 if l > minLength { 45 dst.ScaleVec(1/l, dst) 46 return 47 } 48 } 49 }