-
Notifications
You must be signed in to change notification settings - Fork 0
/
unit_vector.go
49 lines (43 loc) · 1.17 KB
/
unit_vector.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Copyright ©2020 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package distmat
import (
"math/rand"
"github.com/gopherd/gonum/mat"
"github.com/gopherd/gonum/stat/distuv"
)
// UnitVector is a uniform distribution over the surface of a sphere.
type UnitVector struct {
norm distuv.Normal
}
// NewUnitVector constructs a unit vector generator.
func NewUnitVector(src rand.Source) *UnitVector {
return &UnitVector{norm: distuv.Normal{Mu: 0, Sigma: 1, Src: src}}
}
// UnitVecTo sets dst to be a random unit-length vector.
//
// This uses the algorithm of Mueller from:
// https://dl.acm.org/doi/10.1145/377939.377946
// and summarized at:
// https://mathworld.wolfram.com/HyperspherePointPicking.html
//
// UnitVecTo panics if dst has 0 length.
func (u *UnitVector) UnitVecTo(dst *mat.VecDense) {
r := dst.Len()
if r == 0 {
panic(zeroDim)
}
for {
for i := 0; i < r; i++ {
dst.SetVec(i, u.norm.Rand())
}
l := mat.Norm(dst, 2)
// Use l only if it is not too short. Otherwise try again.
const minLength = 1e-5
if l > minLength {
dst.ScaleVec(1/l, dst)
return
}
}
}