Created
January 16, 2010 09:04
-
-
Save dejw/278748 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 "SimpleAgents" | |
| require "actions" # FIXME: duza litera | |
| require "example-services" | |
| require "mocha" | |
| require "main" # FIXME: bootstrap o nazwie Starter | |
| # FIXME: ma ladowac wszystkie pliki zeby dalo sie podlaczac gemy | |
| #require "visualization" # FIXME: duza litera | |
| require "NameService" | |
| require "CommunicationProtocol" | |
| include SimpleGeneticAlgorithm | |
| #class NameService | |
| # def initialize(bus) | |
| # (@mock = Mocha::Mock.new).stubs(:register_address).returns("Genetic", "Simple1", "Aggregate1", "Simple2", "Simple3") | |
| # end | |
| # def register_address(suggest) | |
| # @mock.register_address | |
| # end | |
| #end | |
| class CommunicationService | |
| def priority | |
| -1/0.0 | |
| end | |
| def initialize(bus) | |
| @bus = bus | |
| @listeners = Hash.new | |
| @queue = [] | |
| @mutex = Mutex.new | |
| @cond = ConditionVariable.new | |
| end | |
| def get_nameservice_address(*args) | |
| "localhost" | |
| end | |
| def init | |
| @bus.get(:logger).info("Communication: init") | |
| @running = true | |
| @thread = Thread.new do | |
| @bus.get(:logger).info("Communication: start") | |
| @mutex.synchronize do | |
| while running? do | |
| @bus.get(:logger).info("Communication: wait for message") | |
| @cond.wait(@mutex) if @queue.empty? | |
| until @queue.empty? do | |
| agent, message, listener = @queue.shift | |
| @bus.get(:logger).info("Communication: sending '#{listener}' -> '#{agent}'") | |
| Thread.new do | |
| @listeners[agent].on_received_message(message, listener, listener) | |
| @bus.get(:logger).info("Communication: sent '#{listener}' -> '#{agent}'") | |
| end | |
| 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) | |
| @bus.get(:logger).info("Communication: registering '#{name}'") | |
| @listeners[name] = l | |
| end | |
| def send_unicast_message_to_agent(agentname, message, listener) | |
| send_unicast_message(nil, listener, message, listener) | |
| end | |
| def send_unicast_message(node_address, service_name, message, listener) | |
| # if service_name != listener | |
| @mutex.synchronize do | |
| raise "listener named '#{service_name}' does not exist!" unless @listeners.has_key?(service_name) | |
| @queue.push([service_name, message, listener]) | |
| @cond.signal | |
| end | |
| # else | |
| # @listeners[service_name].on_received_message(message, listener, listener) | |
| # end | |
| end | |
| end | |
| class Service < CoreService::Service | |
| def priority | |
| 100 | |
| end | |
| # ----- | |
| def start | |
| raise StateError, "Service not initialized!" if @state != :initialized | |
| @state = :running | |
| self.children.each_value { |agent| agent.start } | |
| end | |
| def send_remote_message( msg ) | |
| raise StateError, "Service not initialized!" if @state != :initialized | |
| @remote_msg_mutex.synchronize do | |
| @mailbox.put( self, msg ) | |
| @new_msg_condition.signal | |
| end | |
| end | |
| def wait_for_remote_message | |
| @thread = Thread.new do | |
| @remote_msg_mutex.synchronize do | |
| while running? or @state == :initialized do | |
| # Oczekuj na wiadomosc z zewnatrz | |
| @bus.get(:logger).info("CoreService: wait for remote message") | |
| @new_msg_condition.wait( @remote_msg_mutex ) unless @mailbox.has_messages?(self) | |
| @bus.get(:logger).info("CoreService: received remote message") | |
| while message = @mailbox.get( self ) do | |
| process_remote_message( message ) | |
| end | |
| end | |
| end | |
| end | |
| end | |
| # ---- | |
| 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 | |
| self.wait_for_remote_message | |
| @bus.get(:logger).info("CoreService: init") | |
| end | |
| def register_address(suggest = nil) | |
| @bus.get(:nameServiceProxy).register_address | |
| end | |
| end | |
| class GeneticWorkplace < CoreService::Workplace | |
| # ---- Do przeniesienia do CoreService/Agent.rb ----- | |
| def on_received_message(message, sender, *args) | |
| raise NotImplementerError, "!!" | |
| end | |
| def dispatch_moa_message(address, message) | |
| if address == self.address | |
| receiveMOAMessage(message) | |
| #self.send_message(address, :moa, message) | |
| else | |
| @agents.each_value do |agent| | |
| agent.dispatch_moa_message(address, message) | |
| end | |
| end | |
| 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.logger.info("Genetic: gen_operators = [#{@gen_operators.collect(&:class).join(", ")}]") | |
| self.population_size = @init_size | |
| self['best_evaluation'] = @fit_function.evaluate(@population[0]) | |
| self['best_inidividual'] = @gen_repr.copy_individual(@population[0]) | |
| self[:iteration] = @iterations | |
| @last_population = evaluate_population() | |
| end | |
| def perform | |
| self.fetch_all_messages | |
| pop_distribution = Array.new(@population_size) | |
| pop_evaluation = @last_population | |
| self[:iteration] = self.stop_condition.times if self.stop_condition.times % 100 == 0 | |
| 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| | |
| @population_size.times do | |
| selected_individuals.clear | |
| selected_indices.clear | |
| (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 = self['best_evaluation'] | |
| best_current_individual = self['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 < self['best_evaluation'] | |
| self['best_evaluation'] = best_current_evaluation | |
| self['best_inidividual'] = @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 MOA::Observer | |
| def initialize(bus) | |
| @bus = bus | |
| @mutex = Mutex.new | |
| @cond = ConditionVariable.new | |
| @bus.get(:logger).info("#{self.class}: init") | |
| end | |
| def start | |
| @running = true | |
| @thread = Thread.new do | |
| @bus.get(:logger).info("#{self.class}: start") | |
| @bus.get(:logger).info("#{self.class}: getting properties") | |
| props = @bus.get(:moaService).getProperties("test", "Genetic") | |
| @bus.get(:logger).info("#{self.class}: received properties: #{props.inspect}") | |
| props.each_key do |key| | |
| @bus.get(:moaService).register(self, "Genetic", key) | |
| end | |
| @bus.stopped(self) | |
| end | |
| end | |
| def update(observable, property, value) | |
| @bus.get(:logger).info("#{self.class}: #{observable} has changed '#{property}' to #{value.inspect}") | |
| end | |
| end | |
| class SimpleObserver < GeneticObserver | |
| def start | |
| @running = true | |
| @thread = Thread.new do | |
| @bus.get(:logger).info("#{self.class}: start") | |
| @bus.get(:logger).info("#{self.class}: getting properties") | |
| props = @bus.get(:moaService).getProperties("test", "Simple2") | |
| @bus.get(:logger).info("#{self.class}: received properties: #{props.inspect}") | |
| props.each_key do |key| | |
| @bus.get(:moaService).register(self, "Simple2", key) | |
| end | |
| @bus.stopped(self) | |
| end | |
| end | |
| end | |
| class MutationStrategy | |
| def initialize(agent) | |
| @agent = agent | |
| end | |
| def run | |
| for i in @agent.individuals | |
| i.each_with_index do |element, idx| | |
| i[idx] += rand(3) * (rand(2) == 0 ? 1 : -1) | |
| end | |
| end | |
| end | |
| end | |
| class MyAggregate < Aggregate | |
| after :init do | |
| logger.info("#{self.address}: init") | |
| end | |
| end | |
| class MySimpleAgent < SimpleAgent | |
| attr_accessor :individuals | |
| after :init do | |
| logger.info("#{self.address}: init") | |
| self['best_sum'] = 0 | |
| @individuals ||= [] | |
| end | |
| after :step do | |
| self['dummy'] = rand() if rand() < 0.1 | |
| for i in @individuals | |
| i[0]=i[1]+i[2] | |
| self['best_sum'] = i[0] if self['best_sum'] < i[0] | |
| end | |
| self.parent.addAction(Actions::UseStrategyAction.new(MutationStrategy.new(self))) if self.parent.respond_to?(:addAction) | |
| end | |
| end | |
| CONFIG = <<EOF | |
| agents_tree: | |
| value: | |
| - genetic | |
| genetic: | |
| class: GeneticWorkplace | |
| setter-parameters: | |
| iterations: 150 | |
| init_size: 1000 | |
| dimension: 2 | |
| gen_operators: | |
| type: array | |
| contents: | |
| 0..15: mutation | |
| children: | |
| - simple | |
| - aggregate | |
| aggregate: | |
| class: MyAggregate | |
| setter-parameters: | |
| agents: | |
| - simple2 | |
| - simple | |
| simple: | |
| class: MySimpleAgent | |
| simple2: | |
| class: MySimpleAgent | |
| setter-parameters: | |
| individuals: | |
| - | |
| - 0 | |
| - 2 | |
| - 3 | |
| - | |
| - 0 | |
| - 7 | |
| - 1 | |
| mutation: | |
| class: SimpleGeneticAlgorithm::MutationOperator | |
| constructor-parameters: | |
| - 1 | |
| crossover: | |
| class: SimpleGeneticAlgorithm::CrossoverOperator | |
| constructor-parameters: | |
| - 1 | |
| EOF | |
| class Bus < Node::Bus | |
| def stopped(service) | |
| super(service) | |
| if service.is_a?(Service) | |
| self.stop | |
| self.wait | |
| end | |
| end | |
| end | |
| SERVICES = { | |
| :logger => ExampleServices::LoggerService, | |
| :configService => Configuration::Configuration, | |
| :moaService => MOA::MOAService, | |
| # :communicationService => CommunicationService, | |
| :communicationService => CommunicationProtocol::Communicator, | |
| :nameService => NameService, | |
| :nameServiceProxy => NameServiceProxy, | |
| :coreService => Service, | |
| :simpleObserver => SimpleObserver, | |
| :geneticObserver => GeneticObserver, | |
| } | |
| #bus = Bus.new(SERVICES) | |
| #bus.get(:configService).set_configuration(YAML::load(config.gsub("\t", " "))) | |
| #bus.start | |
| #bus.wait | |
| # ------- | |
| # FIXME: metoda readConfiguration() powinna rzucac bledem jesli nie ma pliku! | |
| class MyApp < Wx::App | |
| def on_init | |
| @serwer = PluginSerwer.new(self) | |
| @serviceData = Hash.new | |
| @services = SERVICES.merge({:starter => self}) | |
| @bus = Node::Bus.new(@services) | |
| @serviceData[:bus] = @bus | |
| # @serwer.readConfiguration("config.yml") # TODO: parametryzacja ladowania zeby nie zmieniac kodu o zgrozo | |
| @bus.get(:configService).set_configuration(YAML::load(CONFIG.gsub("\t", " "))) | |
| (@frame = StarterFrame.new(self)).show | |
| @window = @frame | |
| end | |
| end | |
| begin | |
| MyApp.new.main_loop | |
| rescue Exception => e | |
| puts e.message | |
| puts e.backtrace | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment