Skip to content

Instantly share code, notes, and snippets.

@dejw
Created January 12, 2010 20:56
Show Gist options
  • Select an option

  • Save dejw/275608 to your computer and use it in GitHub Desktop.

Select an option

Save dejw/275608 to your computer and use it in GitHub Desktop.
require "rubygems"
require "Node"
require "Configuration"
require "CoreService"
require "MonitoringObjectsAttributes"
require "sga"
require "example-services"
require "mocha"
include SimpleGeneticAlgorithm
class NameService
def initialize(bus)
(@mock = Mocha::Mock.new).stubs(:register_address).returns("Genetic")
end
def register_address(suggest)
@mock.register_address
end
end
module MonitoringObjectsAttributes::Observable
def properties
@properties ||= MonitoringObjectsAttributes::MonitoredHash.new(self)
end
def [](prop)
self.properties[prop]
end
def []=(prop, value)
self.properties[prop] = value
end
attr_reader :observers
end
class CommunicationService
def initialize(bus)
@bus = bus
@listeners = Hash.new
@queue = []
@mutex = Mutex.new
@cond = ConditionVariable.new
@bus.get(:logger).info("Communication: init")
end
def init
@running = true
@thread = Thread.new do
@bus.get(:logger).info("Communication: start")
@mutex.synchronize do
while running? do
@cond.wait(@mutex) if @queue.empty?
until @queue.empty? do
agent, message, listener = @queue.shift
@listeners[agent].on_received_message(message, listener)
end
end
@bus.stopped(self)
end
end
end
def running?
@running
end
def stop
@mutex.synchronize do
@running = false
@cond.signal
end
end
def register_listener(l, name)
@listeners[name] = l
end
def send_unicast_message_to_agent(agentname, message, listener)
@mutex.synchronize do
raise "listener named '#{agentname}' does not exist!" unless @listeners.has_key?(agentname)
@queue.push([agentname, message, listener])
@cond.signal
end
end
def send_unicast_message(node_address, service_name, message, listener)
send_unicast_message_to_agent(service_name, message, listener)
end
end
class Service < CoreService::Service
def notify(who)
self.logger.info("CoreService: '#{who.address}' stopped")
super(who)
end
def detached
self.logger.debug("CoreService: detached")
end
def init
super()
self.children.each do |address, agent|
@bus.get(:communicationService).register_listener(agent, address)
end
end
end
class GeneticAlgorithm < CoreService::Workplace
# ---- Do przeniesienia do CoreService/Agent.rb -----
def on_received_message(message, sender, *args)
message.type = :getProperties if message.type == :getproperties # Hack! Hack! Hack!
logger.info("#{self.address}: received message typed as '#{message.type}' from '#{sender}'")
self.service.send_message(self.address, :moa, message) # TODO: rzutowanie typow ?
end
with_message :moa do
logger.info("#{self.address}: MoaMessage: #{receiveMOAMessage(self.message.content)}")
end
def sendMOAMessage(where, msg)
self.service.send_node_message(where, :moaService, msg)
end
after :init do
@observers = Hash.new
end
# ----
# gen_operators - operatory genetyczne (dowolna liczba argumentow klasy pochodnej od GeneticOperator)
attr_writer :dimension, :gen_operators, :init_size, :iterations
after :init do
@gen_operators ||= []
@fit_function = FitnessFunction.new(@dimension)
@gen_repr = GenotypeRepresentation.new(@dimension)
self.stop_condition = CoreService::Condition::Times.new(@iterations)
self.logger.info("Genetic: dimension = #{@dimension}")
self.logger.info("Genetic: population_size = #{@init_size}")
self.logger.info("Genetic: iterations = #{@iterations}")
self.population_size = @init_size
self['best_evaluation'] = @best_evaluation = @fit_function.evaluate(@population[0])
@best_individual = @gen_repr.copy_individual(@population[0])
@last_population = evaluate_population()
end
def perform
self.fetch_all_messages
if rand() < 0.01
self['best_evaluation'] = @best_evaluation = @best_evaluation - 20
end
pop_distribution = Array.new(@population_size)
pop_evaluation = @last_population
eval_sum = pop_evaluation.inject(0) { |sum, eval| sum + eval }
# wygeneruj dystrybuante rozkladu prawdopodobienstw wyboru osobnikow do nowej populacji
pop_distribution[0] = 1 - pop_evaluation[0]/eval_sum
1.upto(@population_size-2) { |i| pop_distribution[i] = pop_distribution[i-1] + (1 - pop_evaluation[0]/eval_sum) }
pop_distribution[@population_size-1] = 1.0
# stworz nowa populacje
new_population = Array.new(@population_size)
0.upto(@population_size-1) do |index|
i = give_index(pop_distribution)
new_population[index] = @gen_repr.copy_individual(@population[i])
end
# przeprowadz mutacje wedlug kolejnych operatorow
selected_individuals = Array.new
selected_indices = Array.new
@gen_operators.each do |operator|
selected_individuals.clear
selected_indices.clear
@population_size.times do
(operator.no_of_args).times do
i = rand(@population_size)
selected_individuals.push(new_population[i])
selected_indices.push(i)
end
mutated_individuals = operator.perform(*selected_individuals)
selected_indices.each_with_index { |i, index| new_population[i] = mutated_individuals[index] }
end
end
@population = new_population
# ocen biezaca populacje (po wykonaniu operatorow genetycznych)
@last_population = evaluate_population()
end
protected
# Akcesor umozliwiajacy ustawienie nowej liczebnosci populacji.
def population_size=(pop_size)
if pop_size != @population_size
raise ArgumentError.new("Population size must be positive integer") unless pop_size > 0
@population_size = pop_size
reset_population()
end
end
# Usuwa aktualna populacje i generuje nowa.
def reset_population
(@population ||=[]).clear
0.upto(@population_size-1) { @population.push(@gen_repr.create_individual) }
@best_current_evaluation = @fit_function.evaluate(@population[0])
@best_current_individual = @gen_repr.copy_individual(@population[0])
end
# Ocenia poszczegolne osobniki aktualnej populacji - uaktualniajac
# dane najlepszego dotychczas znalezionego osobnika
def evaluate_population()
pop_evaluation = Array.new(@population_size)
best_current_evaluation = @best_evaluation
best_current_individual = @best_inidividual
0.upto(@population_size-1) do |i|
pop_evaluation[i] = @fit_function.evaluate(@population[i])
if pop_evaluation[i] < best_current_evaluation
best_current_evaluation = pop_evaluation[i]
best_current_individual = @gen_repr.copy_individual(@population[i])
end
end
if best_current_evaluation < @best_evaluation
self['best_evaluation'] = @best_evaluation = best_current_evaluation
@best_individual = @gen_repr.copy_individual(best_current_individual)
end
pop_evaluation
end
# Zwraca losowy indeks elementu wedlug podanej dystrybuanty
def give_index(pop_distr)
rand_num = rand
i = 0
until rand_num < pop_distr[i]
i += 1
end
i
end
end
class GeneticObserver
include MonitoringObjectsAttributes::Observer
def initialize(bus)
@bus = bus
@mutex = Mutex.new
@cond = ConditionVariable.new
@bus.get(:logger).info("GeneticObserver: init")
end
def start
@running = true
@thread = Thread.new do
@bus.get(:logger).info("GeneticObserver: start")
@bus.get(:logger).info("GeneticObserver: getting properties")
props = @bus.get(:moaService).getProperties("test", "Genetic") # FIXME: moze jakis timeout ?
@bus.get(:logger).info("GeneticObserver: received properties: #{props.inspect}")
@bus.get(:logger).info("GeneticObserver: registering on '#{props.first.first}'")
@bus.get(:moaService).register(self, "Genetic", props.first.first)
@bus.stopped(self)
end
end
def update(observable, property, value)
@bus.get(:logger).info("GeneticObserver: #{observable} has changed result to #{value}")
end
end
SERVICES = {
:logger => ExampleServices::LoggerService,
:configService => Configuration::Configuration,
:moaService => MonitoringObjectsAttributes::MOAService,
:communicationService => CommunicationService,
:nameService => NameService,
:coreService => Service,
:observer => GeneticObserver,
}
config = <<EOF
agents_tree:
value:
- genetic
genetic:
class: GeneticAlgorithm
autowire: false
setter-parameters:
iterations: 500
init_size: 128
dimension: 20
EOF
class Bus < Node::Bus
def stopped(service)
super(service)
if service.is_a?(Service)
self.stop
self.wait
end
end
end
bus = Bus.new(SERVICES)
bus.get(:configService).set_configuration(YAML::load(config.gsub("\t", " ")))
bus.start
bus.wait
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment