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)
31 attr_accessor :count, :key, :parent
32 def initialize(parent=nil, key=nil)
41 @prev = ChanceHash.new(self, nil) unless @prev
46 @next = ChanceHash.new(nil, self) unless @next
54 attr_reader :next_of, :prev_of
55 def initialize(prev_of=nil, next_of=nil)
56 @hash = Hash.new { |hash, key|
57 hash[key] = ChanceHashValue.new(hash, key)
82 @hash.delete(el) if @hash[el].count == 0
90 @hash.each { |key, val|
93 @picker << [total, key]
101 make_picker unless @valid_pick
110 return @hash.keys.first
112 make_picker unless @valid_pick
114 @picker.each { |ch, el|
115 return el if pick < ch
122 # Word or nonword regexp:
123 # can be used to scan a string splitting it into
124 # words and nonwords.
127 attr_reader :max_order
128 def initialize(ord=5)
129 # mkv[i] holds the chains of order i
131 @mkv = ChanceHash.new
134 def add_forward(array, base=@mkv)
135 return if array.compact.empty?
137 s = sym and sym.to_sym
138 base.increase(s) if s or base != @mkv
139 return if array.empty?
140 add_forward(array, base[s].next) if s or base == @mkv
143 def add_backwards(array, base=@mkv)
144 return if array.compact.empty?
146 s = sym and sym.to_sym
147 base.increase(s) if s or base != @mkv
148 return if array.empty?
149 add_backwards(array, base[s].prev) if s or base == @mkv
153 raise "Too many words in new data" if array.size > @max_order + 1
154 add_forward(array.dup)
155 add_backwards(array.dup)
158 def simple_learn(text)
159 syms = text.scan(WNW).map { |w| w.intern }
163 syms.size.times { |i|
164 ord = [@max_order, syms.size-i].min
166 # puts "Learning #{v.inspect}"
172 def learn(text, o={})
173 opts = {:lowercase => false}.merge o
175 lc = opts[:lowercase]
179 simple_learn(text.downcase)
182 # pp @mkv if defined? pp
185 def raw_next(syms, o={})
186 max_order = o.fetch(:max_order, @max_order)
187 ar = syms.last([max_order, syms.size].min).dup
191 base = base[ar.shift].next
197 syms = text.scan(WNW).map { |w| w.intern }
201 def raw_prev(syms, o={})
202 max_order = o.fetch(:max_order, @max_order)
203 ar = syms.first([max_order, syms.size].min).dup
207 base = base[ar.pop].prev
213 syms = text.scan(WNW).map { |w| w.intern }
217 def complete_prev(text, o={})
218 syms = text.scan(WNW).map { |w| w.intern }
219 prev = raw_prev(syms, o)
222 prev = raw_prev(syms, o)
227 def complete_next(text, o={})
228 syms = text.scan(WNW).map { |w| w.intern }
229 nxt = raw_next(syms, o)
232 nxt = raw_next(syms, o)
237 def complete(text, o={})
240 txt = @mkv.random.to_s
242 syms = txt.scan(WNW).map { |w| w.intern }
243 prev = raw_prev(syms, o)
244 nxt = raw_next(syms, o)
246 # Keep adding only on the side where we
247 # didn't come across a nil already
250 prev = raw_prev(syms, o)
254 nxt = raw_next(syms, o)