require 'lib/mapper_base'
module Mapper
class Generator < Base
def initialize *args
super
@random = Kernel
@generated_count = 0
end
def random= rnd
@random = rnd
@codon.random = rnd
end
attr_reader :random
attr_reader :generated_count
def generate_full required_depth
generate( [:cyclic], required_depth )
end
def generate_grow required_depth
generate( [:cyclic, :terminating], required_depth )
end
def generate( recursivity, required_depth )
@generated_count += 1
@fading = nil
genome = []
tokens = [ Token.new( :symbol, @grammar.start_symbol, 0 ) ]
until ( selected_indices = find_nonterminals( tokens ) ).empty?
selected_index = generate_locus( selected_indices, genome )
selected_token = tokens[selected_index]
selected_symbol = selected_token.data
return genome if @grammar[selected_symbol].recursivity == :infinite
rec = (selected_token.depth < required_depth) ? recursivity : [:terminating]
expansion = generate_rule( rec, selected_token, genome, required_depth-selected_token.depth )
expansion.each { |t| t.depth = selected_token.depth+1 }
tokens = apply_expansion( tokens, expansion, selected_index )
end
genome
end
protected
def generate_rule( recurs, symbol_token, genome, allowed_depth )
rule = pick_expansions( symbol_token, genome )
allowed = filter_expansions_by_depth( rule, allowed_depth )
alts = allowed.find_all { |alt| recurs.include? alt.recursivity }
alts = allowed if alts.empty? if @consume_trivial_codons or rule.size > 1
alt = alts.at @random.rand( alts.size )
genome << @codon.generate( rule.size, rule.index(alt), symbol_token.data )
else
alt = rule.first
end
expansion = alt.deep_copy
modify_expansion_generate( expansion, genome )
return use_expansion( symbol_token, expansion )
end
def filter_expansions_by_depth( rule, allowed_depth )
allowed = rule.find_all { |alt| not alt.min_depth.nil? and alt.min_depth <= allowed_depth }
raise "Generator: required_depth<min_depth, please increase sensible_depth" if allowed.empty?
allowed
end
end
module LocusFirst
protected
def generate_locus( selected_indices, genome )
selected_indices.first
end
end
module LocusGenetic
protected
def generate_locus( selected_indices, genome )
if @consume_trivial_codons or selected_indices.size > 1
index = @random.rand( selected_indices.size )
genome << @codon.generate( selected_indices.size, index )
else
index = 0
end
selected_indices.at index
end
end
module ConstantsNoSupport
def modify_expansion_generate( exp, genome )
exp
end
end
end