class Markov::Chain

Attributes

name[R]
new_words[R]
order[R]
transition_matrices[R]
words[R]

Public Class Methods

new(name: 'anonymous', order: 2, new_words: false) click to toggle source
# File lib/markov/chain.rb, line 9
def initialize(name: 'anonymous', order: 2, new_words: false)
  @name = name
  @order = order
  @words = []
  @new_words = new_words

  @transition_matrices = 1.upto(order+1).map do |depth|
    TransitionMatrix.new(depth: depth)
  end
end

Public Instance Methods

count_syllables(s) click to toggle source
# File lib/markov/chain.rb, line 20
def count_syllables(s)
  s.scan(/[aiouy]+e*|e(?!d$|ly).|[td]ed|le$/).size
end
generate!(max: 1_000, start_text: "", show: false) { |ch| ... } click to toggle source
# File lib/markov/chain.rb, line 69
def generate!(max: 1_000, start_text: "", show: false) #, original: true)
  generated_count = 0
  generated_text = start_text.chars
  word = nil

  until max && (generated_count +=1)>=max
    word = generate_word!(context: new_words ? ["\n"] : generated_text)

    if show
      word.chars.each do |ch|
        sleep 0.05 + rand*(0.01)
        yield ch
      end
    end

    generated_count += word.chars.count
    generated_text += word.chars
  end

  generated_text.join
end
generate_word!(context: ["\n"]) click to toggle source
# File lib/markov/chain.rb, line 91
def generate_word!(context: ["\n"])
  if new_words
    word = @words.first
    until !@words.include?(word.chomp) && word.chomp.match(/^[A-Z][a-z]+$/)
      word = (generate_any_word!) #.chomp #(context: generated_text)
    end
    @words.push(word.chomp)
    word
  else
    generate_any_word!(context: context) #generated_text)
  end    
end
parse(text) click to toggle source
# File lib/markov/chain.rb, line 42
def parse(text)
  puts "---> PARSE TEXT!"
  puts "     Analyzing character distribution..."
  text.gsub!(/[^A-Za-z \n]/, '')
  @transition_matrices.each do |matrix|
    cons_chars = text.chars.each_cons(matrix.depth)
    progress_bar = ProgressBar.create(
      title: "Parsing characters (depth #{matrix.depth})",
      total: cons_chars.count
    )
    cons_chars.each do |word_group|
      matrix.add_transition(word_group)
      progress_bar.increment
    end
  end

  puts "     Analyzing prosody..."
  @words = text.gsub(/[^A-Za-z \n]/,'').split(/[\n ]/).map(&:strip)
  puts "---> done!"
end
predict_next_state(last_states) click to toggle source
# File lib/markov/chain.rb, line 63
def predict_next_state(last_states)
  transition_probabilities = transitions_from(last_states)
  next_state = RandomEvent.new(transition_probabilities)
  next_state.predict!
end
transitions_from(states, primary: true) click to toggle source
# File lib/markov/chain.rb, line 24
def transitions_from(states, primary: true)
  states = [states] unless states.is_a?(Array)

  matrices = @transition_matrices.reverse

  candidate_matrix = matrices.
    select { |m| states.count >= m.depth - 1 }.
    detect do |matrix|
      matrix.transitions_from(states)
    end

  if candidate_matrix
    candidate_matrix.transitions_from(states)
  else
    {}
  end
end

Private Instance Methods

generate_any_word!(context: ["\n"]) click to toggle source
# File lib/markov/chain.rb, line 105
def generate_any_word!(context: ["\n"])
  generated_chars = []
  char = ''
  until char.match(/[ .,;!?\n]/)
    char = predict_next_state(context+generated_chars)
    generated_chars.push(char)
  end
  generated_chars.join
end