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)
56 @hash.delete(el) if @hash[el] == 0
67 @picker << [total, el]
78 return @hash.keys.first
80 make_picker unless @valid_pick
82 @picker.each { |ch, el|
83 return el if pick < ch
90 # Word or nonword regexp:
91 # can be used to scan a string splitting it into
95 attr_reader :max_order
97 # mkv[i] holds the chains of order i
99 @mkv = Array.new(@max_order+1) { |i|
103 Hash.new { |hash, key|
104 hash[key] = {:prev => ChanceHash.new, :next => ChanceHash.new}
111 s = sym.to_sym rescue nil
115 def add_before(array, prev)
116 raise "Not enough words in new data" if array.empty?
117 raise "Too many words in new data" if array.size > @max_order
119 h = @mkv[size][array.dup]
120 h[:prev].increase(prev)
123 def add_after(array, nxt)
124 raise "Not enough words in new data" if array.empty?
125 raise "Too many words in new data" if array.size > @max_order
127 h = @mkv[size][array.dup]
128 h[:next].increase(nxt)
132 raise "Too many words in new data" if array.size > @max_order + 1
133 add_before(array.butfirst, array.first)
134 add_after(array.butlast, array.last)
145 def simple_learn(text)
146 syms = text.scan(WNW).map { |w| w.intern }
150 syms.size.times { |i|
151 ([@max_order, syms.size-i].min+1).times { |ord|
153 # puts "Learning #{v.inspect}"
160 def learn(text, o={})
161 opts = {:lowercase => false}.merge o
163 lc = opts[:lowercase]
167 simple_learn(text.downcase)
170 pp @mkv if defined? pp
173 def raw_next(syms, o={})
174 max_order = o.fetch(:max_order, @max_order)
175 ar = syms.last([max_order, syms.size].min)
180 if @mkv[ord].key?(ar)
181 @mkv[ord][ar][:next].random
183 raw_next(ar.last(ord-1), o)
189 syms = text.scan(WNW).map { |w| w.intern }
193 def raw_prev(syms, o={})
194 max_order = o.fetch(:max_order, @max_order)
195 ar = syms.first([max_order, syms.size].min)
200 if @mkv[ord].key?(ar)
201 @mkv[ord][ar][:prev].random
203 raw_prev(ar.first(ord-1), o)
209 syms = text.scan(WNW).map { |w| w.intern }
213 def complete_prev(text, o={})
214 syms = text.scan(WNW).map { |w| w.intern }
215 prev = raw_prev(syms, o)
218 prev = raw_prev(syms, o)
223 def complete_next(text, o={})
224 syms = text.scan(WNW).map { |w| w.intern }
225 nxt = raw_next(syms, o)
228 nxt = raw_next(syms, o)
233 def complete(text, o={})
236 txt = @mkv[0].random.to_s
238 syms = txt.scan(WNW).map { |w| w.intern }
239 prev = raw_prev(syms, o)
240 nxt = raw_next(syms, o)
242 # Keep adding only on the side where we
243 # didn't come across a nil already
246 prev = raw_prev(syms, o)
250 nxt = raw_next(syms, o)