Class: Gargor

Inherits:
Object
  • Object
show all
Defined in:
lib/gargor.rb,
lib/gargor/cli.rb,
lib/gargor/dsl.rb,
lib/gargor/version.rb,
lib/gargor/reporter.rb,
lib/gargor/parameter.rb,
lib/gargor/exceptions.rb,
lib/gargor/individual.rb,
lib/gargor/individuals.rb

Defined Under Namespace

Classes: ArgumentError, CLI, DeployError, Double, Dsl, ExterminationError, GargorError, Individual, Individuals, OptimizeReporter, Parameter, ParameterError, Reporter, ValidationError

Constant Summary collapse

VERSION =
File.read(File.expand_path(File.join(File.dirname(__FILE__),"..","..","VERSION")))

Class Method Summary collapse

Class Method Details

.baseObject



51
52
53
# File 'lib/gargor.rb', line 51

def base
  @@base
end

.crossover(a, b) ⇒ Object



108
109
110
111
112
113
114
115
# File 'lib/gargor.rb', line 108

def crossover a,b
  return a.clone if a.params == b.params
  log "crossover: #{a} #{b}"
  total = a.fitness + b.fitness
  c = Individual.new
  c.params = a.params.clone
  c.overwrite_by(b,b.fitness,total)
end

.debug(message) ⇒ Object



19
20
21
# File 'lib/gargor.rb', line 19

def debug message
  log message,Logger::DEBUG
end

.first_generation?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/gargor.rb', line 72

def first_generation?
  @@generation == 1
end

.float_rand(f, p = @@dsl.fitness_precision) ⇒ Object

浮動小数点対応のrand

Raises:



100
101
102
103
104
105
106
# File 'lib/gargor.rb', line 100

def float_rand(f,p = @@dsl.fitness_precision)
  raise ArgumentError,"max must be > 0" unless f > 0
  f *= p
  i = f.to_i
  f = rand(i)
  f / p.to_f
end

.generationObject



27
28
29
# File 'lib/gargor.rb', line 27

def generation
  @@generation
end

.individualsObject



35
36
37
# File 'lib/gargor.rb', line 35

def individuals
  @@individuals
end

.last_trialsObject



210
211
212
213
# File 'lib/gargor.rb', line 210

def last_trials
  last_trials_at_this_generation +
    (opt("max_generations")-@@generation)*(opt("population")-opt("elite"))
end

.last_trials_at_this_generationObject



206
207
208
# File 'lib/gargor.rb', line 206

def last_trials_at_this_generation
  @@individuals.select{ |i| i.fitness == nil }.count
end

.load_dsl(params_file) ⇒ Object



82
83
84
85
86
87
# File 'lib/gargor.rb', line 82

def load_dsl(params_file)
  @@dsl_file = params_file
  contents = File.read(params_file)
  @@dsl.instance_eval(contents)
  validate
end

.log(message, level = Logger::INFO) ⇒ Object



14
15
16
17
# File 'lib/gargor.rb', line 14

def log message,level=Logger::INFO
  return if $TESTING
  message.to_s.split("\n").each { |line| @@logger.add(level) {line} }
end

.logfile(file) ⇒ Object



198
199
200
# File 'lib/gargor.rb', line 198

def logfile file
  File.expand_path(File.join(File.dirname(@@dsl_file),file))
end

.loggerObject



39
40
41
# File 'lib/gargor.rb', line 39

def logger
  @@logger
end

.logger=(logger) ⇒ Object



43
44
45
# File 'lib/gargor.rb', line 43

def logger= logger
  @@logger = logger
end

.mutateObject



93
94
95
96
97
# File 'lib/gargor.rb', line 93

def mutate
  individual = @@dsl.create_individual
  log "mutate #{individual}"
  individual
end

.mutation?(mutation = opt("mutation")) ⇒ Boolean

Returns:

  • (Boolean)


145
146
147
# File 'lib/gargor.rb', line 145

def mutation? mutation= opt("mutation")
  rand <= mutation
end

.next_generationObject



188
189
190
191
192
193
194
195
196
# File 'lib/gargor.rb', line 188

def next_generation
  log "<== end generation #{@@generation}"
  @@generation += 1
  return false if @@generation > opt("max_generations")

  log "==> next generation #{@@generation}"
  @@prev_generation = @@individuals
  true
end

.opt(name) ⇒ Object



47
48
49
# File 'lib/gargor.rb', line 47

def opt name
  @@dsl.send(name)
end

.options=(options) ⇒ Object



89
90
91
# File 'lib/gargor.rb', line 89

def options= options
  @@dsl.options = options
end

.paramsObject



23
24
25
# File 'lib/gargor.rb', line 23

def params
  @@dsl.params
end

.populateObject



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/gargor.rb', line 172

def populate
  @@individuals = if first_generation?
                    # 第一世代
                    populate_first_generation
                  else
                    # 次世代
                    raise ExterminationError unless prev_count >= 2
                    populate_next_generation
                  end

   @@dsl.save_state(@@individuals) if @@dsl.has_state?

  log "populate:"
  @@individuals.each { |i| log i }
end

.populate_first_generationObject



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/gargor.rb', line 127

def populate_first_generation
  @@base = @@dsl.create_individual.load_now
  individuals = @@dsl.load_state if @@dsl.has_state?
  unless individuals
    individuals = Gargor::Individuals.new
    individuals << base
    until individuals.length >= opt("population")
      individuals << mutate
    end
  end
  Gargor::Individuals.new(individuals.shuffle)
end

.populate_next_generationObject



161
162
163
164
165
166
167
168
169
170
# File 'lib/gargor.rb', line 161

def populate_next_generation
  log "population: #{@@prev_generation.length}"
  individuals = Gargor::Individuals.new(select_elites @@prev_generation,opt("elite"))

  until individuals.length >= opt("population") do
    i = populate_one
    individuals << i unless individuals.has?(i)
  end
  Gargor::Individuals.new(individuals.shuffle)
end

.populate_oneObject



153
154
155
156
157
158
159
# File 'lib/gargor.rb', line 153

def populate_one
  if mutation?
    mutate
  else
    crossover(*select_parents(@@prev_generation))
  end
end

.prev_count(g = @@prev_generation) ⇒ Object

前世代の数



77
78
79
80
# File 'lib/gargor.rb', line 77

def prev_count g = @@prev_generation
  # fitness > 0 適応している個体
  g.select { |i| i.fitness && i.fitness > 0 }.count
end

.prev_generationObject



31
32
33
# File 'lib/gargor.rb', line 31

def prev_generation
  @@prev_generation
end

.select_elites(g, count) ⇒ Object



140
141
142
143
# File 'lib/gargor.rb', line 140

def select_elites g,count
  return [] unless count > 0
  Gargor::Individuals.new(g.sort{ |a,b| a.fitness<=>b.fitness }.last(count))
end

.select_parents(g) ⇒ Object



149
150
151
# File 'lib/gargor.rb', line 149

def select_parents g
  [selection(g),selection(g)]
end

.selection(g) ⇒ Object

Raises:



117
118
119
120
121
122
123
124
125
# File 'lib/gargor.rb', line 117

def selection g
  total = g.inject(0) { |sum,i| sum += i.fitness }
  cur = float_rand(total)
  g.each { |i|
    return i if i.fitness > cur
    cur -= i.fitness
  }
  raise GargorError,"error selection"
end

.startObject



55
56
57
58
59
60
61
62
63
64
# File 'lib/gargor.rb', line 55

def start
  @@logger = Logger.new(STDOUT)
  @@base = nil
  @@individuals = []
  @@prev_generation = nil
  @@generation = 1
  @@dsl = Dsl.new
  @@dsl_file = nil
  true
end

.total_trialsObject



202
203
204
# File 'lib/gargor.rb', line 202

def total_trials
  opt("population")+(opt("population")-opt("elite"))*(opt("max_generations")-1)
end

.validateObject

Raises:



67
68
69
70
# File 'lib/gargor.rb', line 67

def validate
  raise ValidationError,"POPULATION isn't > 0" unless opt("population") > 0
  true
end