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 s = sym.to_sym rescue nil
118 @mkv[nil].increase(s)
121 def add_before(array, prev)
122 raise "Not enough words in new data" if array.empty?
123 raise "Too many words in new data" if array.size > @max_order
125 h[:prev].increase(prev)
128 def add_after(array, nxt)
129 raise "Not enough words in new data" if array.empty?
130 raise "Too many words in new data" if array.size > @max_order
132 h[:next].increase(nxt)
136 raise "Too many words in new data" if array.size > @max_order + 1
137 add_before(array.butfirst, array.first)
138 add_after(array.butlast, array.last)
149 def simple_learn(text)
150 syms = text.scan(WNW).map { |w| w.intern }
154 syms.size.times { |i|
155 ([@max_order, syms.size-i].min+1).times { |ord|
157 # puts "Learning #{v.inspect}"
164 def learn(text, o={})
165 opts = {:lowercase => false}.merge o
167 lc = opts[:lowercase]
171 simple_learn(text.downcase)
174 pp @mkv if defined? pp
177 def raw_next(syms, o={})
178 max_order = o.fetch(:max_order, @max_order)
179 ar = syms.last([max_order, syms.size].min)
181 @mkv[ar][:next].random
183 raw_next(ar.butfirst, o)
188 syms = text.scan(WNW).map { |w| w.intern }
192 def raw_prev(syms, o={})
193 max_order = o.fetch(:max_order, @max_order)
194 ar = syms.first([max_order, syms.size].min)
196 @mkv[ar][:prev].random
198 raw_prev(ar.butlast, o)
203 syms = text.scan(WNW).map { |w| w.intern }
207 def complete_prev(text, o={})
208 syms = text.scan(WNW).map { |w| w.intern }
209 prev = raw_prev(syms, o)
212 prev = raw_prev(syms, o)
217 def complete_next(text, o={})
218 syms = text.scan(WNW).map { |w| w.intern }
219 nxt = raw_next(syms, o)
222 nxt = raw_next(syms, o)
227 def complete(text, o={})
230 txt = @mkv[nil].random.to_s
232 syms = txt.scan(WNW).map { |w| w.intern }
233 prev = raw_prev(syms, o)
234 nxt = raw_next(syms, o)
236 # Keep adding only on the side where we
237 # didn't come across a nil already
240 prev = raw_prev(syms, o)
244 nxt = raw_next(syms, o)