512mb-bot/libraries/markov.lua

124 lines
3.2 KiB
Lua
Raw Permalink Normal View History

2021-11-26 16:38:17 +00:00
local markov = {}
local function node(relations)
2022-05-20 18:20:49 +00:00
local node = {}
local total = 0
for k,v in pairs(relations) do
total = total + v.occurences
end
for k,v in pairs(relations) do
node[k] = {probability = v.occurences/total,occurences = v.occurences}
end
return node
2021-11-26 16:38:17 +00:00
end
local function escape(str)
2022-05-20 18:20:49 +00:00
return str:gsub("([%%%*%(%)%^%.%[%]%+%-%$%?])","%%%1")
2021-11-26 16:38:17 +00:00
end
local function register_words(str,word_list)
2022-05-20 18:20:49 +00:00
local word_list = word_list or {}
str:gsub("%S+",function(word)
if not word_list[word] then
word_list[word] = {}
2021-11-26 16:38:17 +00:00
end
2022-05-20 18:20:49 +00:00
local current_word = word_list[word]
local escaped_word = escape(word)
str:gsub("%s+" .. escaped_word .. "%s+(%S+)",function(word2)
if not current_word[word2] then
current_word[word2] = {}
end
if not current_word[word2].occurences then
current_word[word2].occurences = 1
else
current_word[word2].occurences = current_word[word2].occurences + 1
end
end)
end)
for k,v in pairs(word_list) do
word_list[k] = node(v)
end
return word_list
2021-11-26 16:38:17 +00:00
end
local table_length = function(tab)
2022-05-20 18:20:49 +00:00
local len = 0
for k,v in pairs(tab) do
len = len + 1
end
return len
2021-11-26 16:38:17 +00:00
end
function markov.walk(self,start)
2022-05-20 18:20:49 +00:00
if not self.init then
error("Attempted to use method on uninitialized instances")
end
local random = math.random(0,1e7)/1e7
local words = {}
words.count = 0
local word = nil
if self.net[start] then
while (words.count < 1) and (table_length(self.net[start]) > 0) do
for k,v in pairs(self.net[start]) do
if (random <= v.probability) then
words.count = words.count + 1
table.insert(words,k)
end
end
random = math.random(0,1e7)/1e7
2021-11-26 16:38:17 +00:00
end
end
2022-05-20 18:20:49 +00:00
if words.count > 0 then
word = words[math.random(1,#words)]
end
return word
2021-11-26 16:38:17 +00:00
end
function markov.expand_vocabulary(self,source)
2022-05-20 18:20:49 +00:00
if not self.init then
error("Attempted to use method on uninitialized instances")
end
self.net = register_words(source,self.net)
2021-11-26 16:38:17 +00:00
end
function markov.save_state(self)
2022-05-20 18:20:49 +00:00
return self.net
2021-11-26 16:38:17 +00:00
end
function markov.load_state(self,new_state)
2022-05-20 18:20:49 +00:00
self.net = new_state
2021-11-26 16:38:17 +00:00
end
function markov.run(self,start,count)
2022-05-20 18:20:49 +00:00
if not self.init then
error("Attempted to use an instance method on an uninitialized instance")
2021-11-26 16:38:17 +00:00
end
2022-05-20 18:20:49 +00:00
if not start then
for k,v in pairs(self.net) do
start = k
break
end
end
local sequence = ""
local current_word = start
while current_word do
sequence = sequence..current_word.." "
local _,counter = sequence:gsub("(%S+)","%1")
current_word = self:walk(current_word)
if counter > (count or 200) then
sequence = sequence:sub(1,-2).."..."
break
end
2021-11-26 16:38:17 +00:00
end
2022-05-20 18:20:49 +00:00
return sequence
2021-11-26 16:38:17 +00:00
end
function markov.new(str)
2022-05-20 18:20:49 +00:00
local self = setmetatable({},{__index = markov})
self.net = register_words(str or "")
self.init = true
return self
2021-11-26 16:38:17 +00:00
end
return markov