forked from smartwalle/aliasmethod
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaliasmethod.go
More file actions
119 lines (94 loc) · 2.09 KB
/
Copy pathaliasmethod.go
File metadata and controls
119 lines (94 loc) · 2.09 KB
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package aliasmethod
import (
"container/list"
"math/rand"
"time"
"errors"
)
type AliasMethod struct {
alias []int
probability []float64
}
func NewAliasMethod(p []float64) (alias *AliasMethod, err error) {
if p == nil {
return nil, errors.New("概率不能为空")
}
if len(p) == 0 {
return nil, errors.New("概率不能为空")
}
alias = &AliasMethod{}
alias.preprocess(p)
return alias, nil
}
func (this *AliasMethod) preprocess(prob []float64) (err error) {
var p = make([]float64, len(prob))
copy(p, prob)
this.alias = make([]int, len(p))
this.probability = make([]float64, len(p))
var average float64 = 1.0 / float64(len(p))
var small = list.New()
var large = list.New()
for index, value := range p {
if value >= average {
large.PushBack(index)
} else {
small.PushBack(index)
}
}
for {
var smallElement *list.Element = small.Back()
var largeElement *list.Element = large.Back()
if smallElement == nil || largeElement == nil {
break
}
var less int = 0;
var more int = 0;
if v, ok := smallElement.Value.(int); ok {
less = v
}
if v, ok := largeElement.Value.(int); ok {
more = v
}
this.probability[less] = p[less] * float64(len(p))
this.alias[less] = more
p[more] = p[more] + p[less] - average
if (p[more] >= 1.0 / float64(len(p))) {
large.PushBack(more)
} else {
small.PushBack(more)
}
large.Remove(largeElement)
small.Remove(smallElement)
}
for {
var smallElement *list.Element = small.Back()
if smallElement == nil {
break
}
if v, ok := smallElement.Value.(int); ok {
this.probability[v] = 1.0
}
small.Remove(smallElement)
}
for {
var largeElement *list.Element = large.Back()
if largeElement == nil {
break
}
if v, ok := largeElement.Value.(int); ok {
this.probability[v] = 1.0
}
large.Remove(largeElement)
}
return err
}
func (this *AliasMethod) Next() int {
rand.Seed(time.Now().UnixNano())
var column = rand.Intn(len(this.probability))
var f = rand.Float64()
var coinToss = f < this.probability[column]
if coinToss {
return column
}
return this.alias[column]
}