Function reference in Ruby Array

Asked

Viewed 73 times

0

I couldn’t understand what the Ruby relation of the reference of an array variable is like (best and vector) with the return of a function (fitness or bitstring for example).

Consider the next case:

best[:fitness]

Where best is an array and fitness is a function, what will be prompted in the array variable ? and what will be referenced by the function ?

See the full code:

def objective_function(vector)
    return vector.inject(0.0) {|sum, x| sum + (x ** 2.0)}
end

def random_bitstring(num_bits)
    return (0...num_bits).inject(""){|s,i| s<<((rand<0.5) ? "1" : "0")}
end

def decode(bitstring, search_space, bits_per_param)
    vector = []
    search_space.each_with_index do |bounds, i|
        off, sum = i*bits_per_param, 0.0
        param = bitstring[off...(off+bits_per_param)].reverse
        param.size.times do |j|
            sum += ((param[j].chr=='1') ? 1.0 : 0.0) * (2.0 ** j.to_f)
        end
        min, max = bounds
        vector << min + ((max-min)/((2.0**bits_per_param.to_f)-1.0)) * sum
    end
    return vector
end

def fitness(candidate, search_space, param_bits)
    candidate[:vector]=decode(candidate[:bitstring], search_space, param_bits)
    candidate[:fitness] = objective_function(candidate[:vector])
end

def binary_tournament(pop)
    i, j = rand(pop.size), rand(pop.size)
    j = rand(pop.size) while j==i
    return (pop[i][:fitness] < pop[j][:fitness]) ? pop[i] : pop[j]
end

def point_mutation(bitstring, rate=1.0/bitstring.size)
    child = ""
    bitstring.size.times do |i|
        bit = bitstring[i].chr
        child << ((rand()<rate) ? ((bit=='1') ? "0" : "1") : bit)
    end
    return child
end

def crossover(parent1, parent2, rate)
    return ""+parent1 if rand()>=rate
    child = ""
    parent1.size.times do |i|
        child << ((rand()<0.5) ? parent1[i].chr : parent2[i].chr)
    end
    return child
end

def reproduce(selected, pop_size, p_cross, p_mut)
    children = []
    selected.each_with_index do |p1, i|
        p2 = (i.modulo(2)==0) ? selected[i+1] : selected[i-1]
        p2 = selected[0] if i == selected.size-1
        child = {}
        child[:bitstring] = crossover(p1[:bitstring], p2[:bitstring], p_cross)
        child[:bitstring] = point_mutation(child[:bitstring], p_mut)
        children << child
        break if children.size >= pop_size
    end
    return children
end

def bitclimber(child, search_space, p_mut, max_local_gens, bits_per_param)
    current = child
    max_local_gens.times do
        candidate = {}
        candidate[:bitstring] = point_mutation(current[:bitstring], p_mut)
        fitness(candidate, search_space, bits_per_param)
        current = candidate if candidate[:fitness] <= current[:fitness]
    end
    return current
end

def search(max_gens, search_space, pop_size, p_cross, p_mut, max_local_gens, p_local, bits_per_param=16)
    pop = Array.new(pop_size) do |i| {:bitstring=>random_bitstring(search_space.size*bits_per_param)}
    end
    pop.each{|candidate| fitness(candidate, search_space, bits_per_param) }
    gen, best = 0, pop.sort{|x,y| x[:fitness] <=> y[:fitness]}.first
    max_gens.times do |gen|
        selected = Array.new(pop_size){|i| binary_tournament(pop)}
        children = reproduce(selected, pop_size, p_cross, p_mut)
        children.each{|cand| fitness(cand, search_space, bits_per_param)}
        pop = []
        children.each do |child|
            if rand() < p_local
                child = bitclimber(child, search_space, p_mut, max_local_gens, bits_per_param)
            end
            pop << child
        end
        pop.sort!{|x,y| x[:fitness] <=> y[:fitness]}
        best = pop.first if pop.first[:fitness] <= best[:fitness]
        puts ">gen=#{gen}, f=#{best[:fitness]}, b=#{best[:bitstring]}"
    end
    return best
end

if __FILE__ == $0
    # problem configuration
    problem_size = 3
    search_space = Array.new(problem_size) {|i| [-5, +5]}
    # algorithm configuration
    max_gens = 100
    pop_size = 100
    p_cross = 0.98
    p_mut = 1.0/(problem_size*16).to_f
    max_local_gens = 20
    p_local = 0.5
    # execute the algorithm
    best = search(max_gens, search_space, pop_size, p_cross, p_mut, max_local_gens, p_local)
    puts "done! Solution: f=#{best[:fitness]}, b=#{best[:bitstring]}, v=#{best[:vector].inspect}"
end

Obs: This code is an implementation of a Memetic algorithm, which in turn is a variation of an Evolutionary Algorithm. A Memetic Algorithm technically seeks the best solution to a problem in a set of solutions, from a global search of the results integrated to an optimization every cycle/ generation that selects variations of a good solution from a local search of the results.

My goal is to translate the code to Matlab programming.

  • 1

    best is a Hash (http://ruby-doc.org/core-2.2.3/Hash.html) and best[:fitness] returns the value associated with the key :fitness of the hash best.

1 answer

0

@Guigs said this is it, best is a Hash and :fitness is simply the access key to a position of that hash. I ran your code and for example the end result of best is

{:bitstring=>"011111111111111110000000000000000111111111111111", :vector=>[-7.629510948348184e-05, 7.629510948348184e-05, -7.629510948348184e-05], :fitness=>1.7462831193289442e-08}

So when I access best[:fitness] this will result in the value 1.7462831193289442e-08 which is the corresponding value of the key :fitness

I believe that in Matlab the corresponding structure is the containers.Map (available in version 7.7 (R2008b) data Structure. see MATLAB Map containers for more. It removes some restrictions that STRUCT has, for example:

c = containers.Map
c('fitness') = 1.7462831193289442e-08
keys(c)
values(c)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.