Created
January 12, 2010 20:56
-
-
Save dejw/275608 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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