2 # Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
3 # New markov chain plugin
5 $swig_runtime_data_type_pointer2 = nil
10 "("+self.join(',')+")"
26 return nil if self.empty?
29 count = rand(self.size-i)
31 count = rand([n, self.size-i].min)
36 def pick_with_chance(chance)
40 return el if pick < ch
49 "'" + SQLite3::Database.quote(self)+"'"
60 # Word or nonword regexp:
61 # can be used to scan a string splitting it into
65 attr_reader :max_order
75 def initialize(db, ord=5)
76 @db = SQLite3::Database.new(db)
80 @db.execute("create table if not exists #{order(0).quoted} (#{word(0).quoted} text unique not null primary key, 'chance' integer not null default 0)")
81 1.upto(@max_order+1) do |i|
82 cols = (0..i).map { |j| word(j).quoted}
84 cmd = "create table if not exists "
85 cmd << order(i).quoted + " ("
86 cmd << cols.map { |c| c+' text'}.join(',')
87 cmd << ", 'chance' integer not null default 0"
88 cmd << ", unique#{cols.sql_group})"
94 @db.execute("select word0 from order0")
98 @db.get_first_value("select count(*) from order0").to_i
101 def where_selector(words, o={})
102 offset = o[:offset].to_i
104 words.length.times do |i|
106 ar << word(i+offset) + "=" + words[i].quoted
108 ar << word(i+offset) + " ISNULL"
111 "where #{ar.join(' and ')}"
114 def grouped_selector(words, o={})
115 offset= o[:offset].to_i
118 words.length.times do |i|
120 wds << words[i].quoted
124 wds << o[:chance].to_i
126 return [cols.sql_group, wds.sql_group]
130 # Don't add nil to order 0
132 @db.transaction do |db|
133 if db.get_first_value("select chance from order0 where word0=?1", sym)
134 db.execute("update order0 set chance=chance+1 where word0=?1", sym)
136 db.execute("insert into order0 (word0, chance) values (?1, 1)", sym)
139 # puts @db.execute("select * from order0 where word0=?1", sym).inspect
143 raise "Too many words in new data" if array.size > @max_order + 1
144 table = order(array.length-1).quoted
145 cols, wds = grouped_selector(array, :chance => 1)
146 where = where_selector(array)
147 @db.transaction do |db|
148 if db.get_first_value("select chance from #{table} " + where)
149 db.execute("update #{table} set chance=chance+1 " + where)
151 db.execute("insert into #{table} #{cols} values #{wds}")
154 # puts @db.execute("select * from #{table} " + where).inspect
158 # puts "adding #{data.inspect}"
166 def simple_learn(text)
167 return if text.empty?
168 syms = text.scan(WNW)
172 syms.each_index do |i|
173 max_len = [@max_order+1, syms.size - i].min
174 1.upto max_len do |len|
176 # puts "Learning #{v.inspect}"
183 def learn(text, o={})
184 opts = {:lowercase => false}.merge o
186 lc = opts[:lowercase]
190 simple_learn(text.downcase)
194 def raw_next(syms, o={})
195 max_order = o.fetch(:max_order, @max_order)
196 if max_order > syms.length
197 max_order = syms.length
199 ar = syms.last(max_order)
200 # puts "raw_next #{max_order} #{ar.inspect}"
202 table = order(max_order)
203 sel = word(max_order)
204 where = where_selector(ar)
206 choices = @db.execute("select #{sel},chance from #{table} #{where}")
207 unless choices.empty?
208 sum = @db.get_first_value("select sum(chance) from #{table} #{where}").to_i
209 return choices.pick_with_chance(sum)
211 raw_next(ar.butfirst, o)
216 syms = text.scan(WNW)
220 def raw_prev(syms, o={})
221 max_order = o.fetch(:max_order, @max_order)
222 if max_order > syms.length
223 max_order = syms.length
225 ar = syms.first(max_order)
226 # puts "raw_prev #{max_order} #{ar.inspect}"
228 table = order(max_order)
230 where = where_selector(ar,:offset => 1)
232 choices = @db.execute("select #{sel}, chance from #{table} #{where}")
233 unless choices.empty?
234 sum = @db.get_first_value("select sum(chance) from #{table} #{where}").to_i
235 return choices.pick_with_chance(sum)
237 raw_prev(ar.butlast, o)
242 syms = text.scan(WNW)
246 def complete_prev(text, o={})
247 syms = text.scan(WNW)
248 prev = raw_prev(syms, o)
251 prev = raw_prev(syms, o)
256 def complete_next(text, o={})
257 syms = text.scan(WNW)
258 nxt = raw_next(syms, o)
261 nxt = raw_next(syms, o)
266 def complete(text, o={})
268 choices = @db.execute("select word0,chance from order0")
269 return String.new if choices.empty?
270 sum = @db.get_first_value("select sum(chance) from order0").to_i
272 txt = choices.pick_with_chance(sum)
275 prev = raw_prev(syms, o)
276 nxt = raw_next(syms, o)
278 # puts syms.inspect, nxt.inspect, prev.inspect
279 # Keep adding only on the side where we
280 # didn't come across a nil already
283 prev = raw_prev(syms, o)
287 nxt = raw_next(syms, o)