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
89 # Word or nonword regexp:
90 # can be used to scan a string splitting it into
95 # mkv[i] holds the chains of order i
98 # Each chain is in the form
99 # [:array, :of, :symbols] => {
100 # :prev => ChanceHash,
101 # :next => ChanceHash
103 # except for order 0, which is a simple ChanceHash
105 MAX_ORDER.times { |i|
107 @mkv[0] = ChanceHash.new
109 @mkv[i] = Hash.new { |hash, key|
110 hash[key] = {:prev => ChanceHash.new, :next => ChanceHash.new}
118 s = sym.to_sym rescue nil
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
126 h = @mkv[size][array.dup]
127 h[:prev].increase(prev)
130 def add_after(array, nxt)
131 raise "Not enough words in new data" if array.empty?
132 raise "Too many words in new data" if array.size > MAX_ORDER
134 h = @mkv[size][array.dup]
135 h[:next].increase(nxt)
139 raise "Too many words in new data" if array.size > MAX_ORDER + 1
140 add_before(array.butfirst, array.first)
141 add_after(array.butlast, array.last)
152 def simple_learn(text)
153 syms = text.scan(WNW).map { |w| w.intern }
157 syms.size.times { |i|
158 [MAX_ORDER, syms.size-i].min.times { |ord|
160 # puts "Learning #{v.inspect}"
167 def learn(text, o={})
168 opts = {:lowercase => true}.merge o
170 lc = opts[:lowercase]
174 simple_learn(text.downcase)
177 pp @mkv if defined? pp
181 ar = syms.last([MAX_ORDER, syms.size].min)
186 if @mkv[ord].key?(ar)
187 @mkv[ord][ar][:next].random
189 raw_next(ar.last(ord-1))
195 syms = text.scan(WNW).map { |w| w.intern }
200 ar = syms.first([MAX_ORDER, syms.size].min)
205 if @mkv[ord].key?(ar)
206 @mkv[ord][ar][:prev].random
208 raw_next(ar.first(ord-1))
214 syms = text.scan(WNW).map { |w| w.intern }