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)
64 @hash.delete(el) if @hash[el] == 0
75 @picker << [total, el]
86 return @hash.keys.first
88 make_picker unless @valid_pick
90 @picker.each { |ch, el|
91 return el if pick < ch
98 # Word or nonword regexp:
99 # can be used to scan a string splitting it into
100 # words and nonwords.
103 attr_reader :max_order
104 def initialize(ord=5)
106 @mkv = Hash.new { |hash, key|
107 hash[key] = {:prev => ChanceHash.new, :next => ChanceHash.new}
109 @mkv[nil] = ChanceHash.new
117 # Don't add nil to order 0
119 @mkv[nil].increase(sym.to_sym)
122 def add_before(array, prev)
123 raise "Not enough words in new data" if array.empty?
124 raise "Too many words in new data" if array.size > @max_order
125 # Don't add prev to chains whose first element is nil
126 return unless array.first
128 h[:prev].increase(prev)
131 def add_after(array, nxt)
132 raise "Not enough words in new data" if array.empty?
133 raise "Too many words in new data" if array.size > @max_order
134 # Don't add next to chains whose last element is nil
135 return unless array.last
137 h[:next].increase(nxt)
141 raise "Too many words in new data" if array.size > @max_order + 1
142 add_before(array.butfirst, array.first)
143 add_after(array.butlast, array.last)
154 def simple_learn(text)
155 syms = text.scan(WNW).map { |w| w.intern }
159 syms.size.times { |i|
160 ([@max_order, syms.size-i].min+1).times { |ord|
162 # puts "Learning #{v.inspect}"
169 def learn(text, o={})
170 opts = {:lowercase => false}.merge o
172 lc = opts[:lowercase]
176 simple_learn(text.downcase)
179 pp @mkv if defined? pp
182 def raw_next(syms, o={})
183 max_order = o.fetch(:max_order, @max_order)
184 ar = syms.last([max_order, syms.size].min)
186 @mkv[ar][:next].random
188 raw_next(ar.butfirst, o)
193 syms = text.scan(WNW).map { |w| w.intern }
197 def raw_prev(syms, o={})
198 max_order = o.fetch(:max_order, @max_order)
199 ar = syms.first([max_order, syms.size].min)
201 @mkv[ar][:prev].random
203 raw_prev(ar.butlast, o)
208 syms = text.scan(WNW).map { |w| w.intern }
212 def complete_prev(text, o={})
213 syms = text.scan(WNW).map { |w| w.intern }
214 prev = raw_prev(syms, o)
217 prev = raw_prev(syms, o)
222 def complete_next(text, o={})
223 syms = text.scan(WNW).map { |w| w.intern }
224 nxt = raw_next(syms, o)
227 nxt = raw_next(syms, o)
232 def complete(text, o={})
235 txt = @mkv[nil].random.to_s
237 syms = txt.scan(WNW).map { |w| w.intern }
238 prev = raw_prev(syms, o)
239 nxt = raw_next(syms, o)
241 # Keep adding only on the side where we
242 # didn't come across a nil already
245 prev = raw_prev(syms, o)
249 nxt = raw_next(syms, o)