-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmarkov.go
More file actions
151 lines (134 loc) · 3.62 KB
/
Copy pathmarkov.go
File metadata and controls
151 lines (134 loc) · 3.62 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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package markov
import (
"math/rand"
"strings"
)
//PUBLIC
type Graph interface {
LoadPhrase(string)
GenerateMarkovString() string
}
//Graph is the generic holder of all of the data for a certain graph of words needed to generate a markov chain.
type RamGraph struct {
starters list
allWords list
strings []string
contextDepth int
nodes map[string]*link
}
func NewGraph(depth int) *RamGraph {
var g RamGraph
g.nodes = make(map[string]*link)
g.contextDepth = depth
return &g
}
//LoadPhrase loads a whole phrase (be it a sentence, single word that someone said, or paragraph) into the graph.
//Splits the phrase along spaces in order to load each word into the chain.
func (graph *RamGraph) LoadPhrase(phrase string) {
words := strings.Split(phrase, " ")
// Get the words in reverse order, just to make it easier to input the next word in the chain.
var prevVal *link = nil //Start prevVal as nil, as the first word to appear will be the last one in the phrase.
for i := len(words) - 1; i >= 0; i-- {
depthToGo := lesser(i, graph.contextDepth)
context := make([]*string, depthToGo)
for j := depthToGo; j > 0; j-- {
indexToGrab := i - j
context[j-1] = &words[indexToGrab]
}
prevVal = graph.loadWord(words[i], prevVal, (i == 0), context)
}
}
//GenerateMarkovString generates a random string based off of the current model in the graph.
func (graph *RamGraph) GenerateMarkovString() string {
var ret string
var currLink *link = graph.starters.links[rand.Intn(len(graph.starters.links))]
ret += *currLink.value
currLink = currLink.links[rand.Intn(len(currLink.links))]
for currLink != nil {
ret += " " + *currLink.value
currLink = currLink.links[rand.Intn(len(currLink.links))]
}
return ret
}
//private, implementation details.
type link struct {
value *string
links []*link
context []*string
}
type list struct {
links []*link
}
//loadWord loads a word into the respective graph. It creates a link if one doesn't exist,
// and links the current word to both previous (if higher context is on) and next words.
func (graph *RamGraph) loadWord(val string, nextval *link, starter bool, context []*string) *link {
mapKey := buildMapKey(val, context)
l := graph.nodes[mapKey]
if l == nil {
ctx := make([]*string, len(context))
for i, v := range context {
ctx[i] = graph.findString(*v)
}
l = &link{
value: graph.findString(val),
links: []*link{nextval},
context: ctx,
}
graph.allWords.links = append(graph.allWords.links, l)
graph.nodes[mapKey] = l
} else {
l.links = append(l.links, nextval)
}
if starter {
graph.starters.links = append(graph.starters.links, l)
}
return l
}
func (graph *RamGraph) findInGraph(val string, context []*string) *link {
key := ""
for _, ctx := range context {
key += *ctx + " "
}
key += val
return graph.nodes[key]
// for i, v := range graph.allWords.links {
// if *v.value == val {
// contextMatching := true
// if len(v.context) != len(context) {
// continue
// }
// for j, ctx := range v.context {
// if *ctx != *context[j] {
// contextMatching = false
// }
// }
// if contextMatching {
// return graph.allWords.links[i]
// }
// }
// }
// return nil
}
func (graph *RamGraph) findString(val string) *string {
for i, v := range graph.strings {
if v == val {
return &graph.strings[i]
}
}
graph.strings = append(graph.strings, val)
return &graph.strings[len(graph.strings)-1]
}
func lesser(x int, y int) int {
if x > y {
return y
}
return x
}
func buildMapKey(val string, context []*string) string {
key := ""
for _, ctx := range context {
key += *ctx + " "
}
key += val
return key
}