2 # Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
3 # New markov chain plugin
19 return nil if self.empty?
22 count = rand(self.size-i)
24 count = rand([n, self.size-i].min)
52 @hash.delete(el) if @hash[el] == 0
63 @picker << [total, el]
74 return @hash.keys.first
76 make_picker unless @valid_pick
78 @picker.each { |ch, el|
79 return el if pick < ch
86 # Word or nonword regexp:
87 # can be used to scan a string splitting it into
91 attr_reader :max_order
93 # mkv[i] holds the chains of order i
95 @mkv = Array.new(@max_order+1) { |i|
99 Hash.new { |hash, key|
100 hash[key] = {:prev => ChanceHash.new, :next => ChanceHash.new}
107 s = sym.to_sym rescue nil
111 def add_before(array, prev)
112 raise "Not enough words in new data" if array.empty?
113 raise "Too many words in new data" if array.size > @max_order
115 h = @mkv[size][array.dup]
116 h[:prev].increase(prev)
119 def add_after(array, nxt)
120 raise "Not enough words in new data" if array.empty?
121 raise "Too many words in new data" if array.size > @max_order
123 h = @mkv[size][array.dup]
124 h[:next].increase(nxt)
128 raise "Too many words in new data" if array.size > @max_order + 1
129 add_before(array.butfirst, array.first)
130 add_after(array.butlast, array.last)
141 def simple_learn(text)
142 syms = text.scan(WNW).map { |w| w.intern }
146 syms.size.times { |i|
147 ([@max_order, syms.size-i].min+1).times { |ord|
149 # puts "Learning #{v.inspect}"
156 def learn(text, o={})
157 opts = {:lowercase => true}.merge o
159 lc = opts[:lowercase]
163 simple_learn(text.downcase)
166 pp @mkv if defined? pp
169 def raw_next(syms, o={})
170 max_order = o.fetch(:max_order, @max_order)
171 ar = syms.last([max_order, syms.size].min)
176 if @mkv[ord].key?(ar)
177 @mkv[ord][ar][:next].random
179 raw_next(ar.last(ord-1), o)
185 syms = text.scan(WNW).map { |w| w.intern }
189 def raw_prev(syms, o={})
190 max_order = o.fetch(:max_order, @max_order)
191 ar = syms.first([max_order, syms.size].min)
196 if @mkv[ord].key?(ar)
197 @mkv[ord][ar][:prev].random
199 raw_prev(ar.first(ord-1), o)
205 syms = text.scan(WNW).map { |w| w.intern }
209 def complete_prev(text, o={})
210 syms = text.scan(WNW).map { |w| w.intern }
211 prev = raw_prev(syms, o)
214 prev = raw_prev(syms, o)
219 def complete_next(text, o={})
220 syms = text.scan(WNW).map { |w| w.intern }
221 nxt = raw_next(syms, o)
224 nxt = raw_next(syms, o)
229 def complete(text, o={})
232 txt = @mkv[0].random.to_s
234 syms = txt.scan(WNW).map { |w| w.intern }
235 prev = raw_prev(syms, o)
236 nxt = raw_next(syms, o)
238 # Keep adding only on the side where we
239 # didn't come across a nil already
242 prev = raw_prev(syms, o)
246 nxt = raw_next(syms, o)