Algorithmically 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 90dbca96e9a153e6acfbdd2eac99f9e06054aa73
4
- data.tar.gz: a1a059aab483649dae1d890df74549a20cda0b42
3
+ metadata.gz: c6b37344d80011486740e722946df13475c44ba5
4
+ data.tar.gz: 46afbc8274889d7660acf6fd42f5e3e78260851e
5
5
  SHA512:
6
- metadata.gz: 9afc0731375aa0fae820aa4605b87ce7992f484430faaf0c1eabba5fa91eaf785c36457e4613c2c622e51078667a3ecec57f519243114cd3a0e7765e0c3f4029
7
- data.tar.gz: 7d30e282bc64b82fe5683b33308e218cea14ed76100841f314fc3a02ab14c4399a8faa62ed9e4c5aee866ac4acee44fb37cb1124ca513d1846225cf32fb2a541
6
+ metadata.gz: 1831736b94dc14f2234ebfe1c2ca1c3c33f9d1ff301dd81f070c97bce781e517e38929ba6579467f60fda7093f3d267aa71fc28736850f97ae42c9775c4c75e0
7
+ data.tar.gz: a68582cd9aebbb76d27b047643d5160ba6ce1e352e45299512088dfcfbc326d5a8a2f22b58d21006098b1af2b9cdc7701210c7eb481294af92b99504e71e7066
data/README.md CHANGED
@@ -22,20 +22,20 @@ Or install it yourself as:
22
22
 
23
23
  ### Evolutionary Algorithms
24
24
 
25
- Algorithmically::Genetic.new(100, 64, 100, 0.98)
25
+ Algorithmically::Evolutionary::Genetic.new(100, 64, 100, 0.98)
26
26
 
27
27
  ### Neural Algorithms
28
28
 
29
- Algorithmically::Perceptron.new([[0,0,0], [0,1,1], [1,0,1], [1,1,1]], 2, 20, 0.1)
29
+ Algorithmically::Neural::Perceptron.new([[0,0,0], [0,1,1], [1,0,1], [1,1,1]], 2, 20, 0.1)
30
30
 
31
31
  ### Stochastic Algorithms
32
32
 
33
- Algorithmically::RandomSearch.new(2, 50)
33
+ Algorithmically::Neural::RandomSearch.new(2, 50)
34
34
 
35
- Algorithmically::AdaptiveRandomSearch.new(1000, 2, 0.05, 1.3, 3.0, 10, 30)
35
+ Algorithmically::Neural::AdaptiveRandomSearch.new(1000, 2, 0.05, 1.3, 3.0, 10, 30)
36
36
 
37
- Algorithmically::HillClimbing.new(2, 1000)
37
+ Algorithmically::Neural::HillClimbing.new(2, 1000)
38
38
 
39
- Algorithmically::GuidedLocalSearch.new(150, [[565,575],[25,185],[345,750],[945,685]], 20, 0.3)
39
+ Algorithmically::Neural::GuidedLocalSearch.new(150, [[565,575],[25,185],[345,750],[945,685]], 20, 0.3)
40
40
 
41
41
 
@@ -1,77 +1,79 @@
1
- module Evolutionary
1
+ module Algorithmically
2
+ module Evolutionary
2
3
 
3
- class Genetic
4
+ class Genetic
4
5
 
5
- def initialize(max_gens, num_bits, pop_size, p_crossover)
6
- p_mutation = 1.0/num_bits
7
- best = search(max_gens, num_bits, pop_size, p_crossover, p_mutation)
8
- puts "done! Solution: f=#{best[:fitness]}, s=#{best[:bitstring]}"
9
- end
10
-
11
- def onemax(bitstring)
12
- sum = 0
13
- bitstring.size.times { |i| sum+=1 if bitstring[i].chr=='1' }
14
- sum
15
- end
6
+ def initialize(max_gens, num_bits, pop_size, p_crossover)
7
+ p_mutation = 1.0/num_bits
8
+ best = search(max_gens, num_bits, pop_size, p_crossover, p_mutation)
9
+ puts "done! Solution: f=#{best[:fitness]}, s=#{best[:bitstring]}"
10
+ end
16
11
 
17
- def random_bitstring(num_bits)
18
- (0...num_bits).inject("") { |s, i| s<<((rand<0.5) ? "1" : "0") }
19
- end
12
+ def onemax(bitstring)
13
+ sum = 0
14
+ bitstring.size.times { |i| sum+=1 if bitstring[i].chr=='1' }
15
+ sum
16
+ end
20
17
 
21
- def binary_tournament(pop)
22
- i, j = rand(pop.size), rand(pop.size)
23
- j = rand(pop.size) if j==i
24
- (pop[i][:fitness] > pop[j][:fitness]) ? pop[i] : pop[j]
25
- end
18
+ def random_bitstring(num_bits)
19
+ (0...num_bits).inject("") { |s, i| s<<((rand<0.5) ? "1" : "0") }
20
+ end
26
21
 
27
- def point_mutation(bitstring, rate=1.0/bitstring.size)
28
- child = ""
29
- bitstring.size.times do |i|
30
- bit = bitstring[i].chr
31
- child << ((rand()<rate) ? ((bit=='1') ? "0" : "1") : bit)
22
+ def binary_tournament(pop)
23
+ i, j = rand(pop.size), rand(pop.size)
24
+ j = rand(pop.size) if j==i
25
+ (pop[i][:fitness] > pop[j][:fitness]) ? pop[i] : pop[j]
32
26
  end
33
- child
34
- end
35
27
 
36
- def crossover(parent1, parent2, rate)
37
- ""+parent1 if rand()>=rate
38
- point = 1 + rand(parent1.size-2)
39
- parent1[0...point]+parent2[point...(parent1.size)]
40
- end
28
+ def point_mutation(bitstring, rate=1.0/bitstring.size)
29
+ child = ""
30
+ bitstring.size.times do |i|
31
+ bit = bitstring[i].chr
32
+ child << ((rand()<rate) ? ((bit=='1') ? "0" : "1") : bit)
33
+ end
34
+ child
35
+ end
41
36
 
42
- def reproduce(selected, pop_size, p_cross, p_mutation)
43
- children = []
44
- selected.each_with_index do |p1, i|
45
- p2 = (i.modulo(2)==0) ? selected[i+1] : selected[i-1]
46
- p2 = selected[0] if i == selected.size-1
47
- child = {}
48
- child[:bitstring] = crossover(p1[:bitstring], p2[:bitstring], p_cross)
49
- child[:bitstring] = point_mutation(child[:bitstring], p_mutation)
50
- children << child
51
- children.size >= pop_size
37
+ def crossover(parent1, parent2, rate)
38
+ ""+parent1 if rand()>=rate
39
+ point = 1 + rand(parent1.size-2)
40
+ parent1[0...point]+parent2[point...(parent1.size)]
52
41
  end
53
- children
54
- end
55
42
 
56
- def search(max_gens, num_bits, pop_size, p_crossover, p_mutation)
57
- population = Array.new(pop_size) do |i|
58
- {:bitstring => random_bitstring(num_bits)}
43
+ def reproduce(selected, pop_size, p_cross, p_mutation)
44
+ children = []
45
+ selected.each_with_index do |p1, i|
46
+ p2 = (i.modulo(2)==0) ? selected[i+1] : selected[i-1]
47
+ p2 = selected[0] if i == selected.size-1
48
+ child = {}
49
+ child[:bitstring] = crossover(p1[:bitstring], p2[:bitstring], p_cross)
50
+ child[:bitstring] = point_mutation(child[:bitstring], p_mutation)
51
+ children << child
52
+ children.size >= pop_size
53
+ end
54
+ children
59
55
  end
60
- population.each { |c| c[:fitness] = onemax(c[:bitstring]) }
61
- best = population.sort { |x, y| y[:fitness] <=> x[:fitness] }.first
62
- max_gens.times do |gen|
63
- selected = Array.new(pop_size) { |i| binary_tournament(population) }
64
- children = reproduce(selected, pop_size, p_crossover, p_mutation)
65
- children.each { |c| c[:fitness] = onemax(c[:bitstring]) }
66
- children.sort! { |x, y| y[:fitness] <=> x[:fitness] }
67
- best = children.first if children.first[:fitness] >= best[:fitness]
68
- population = children
69
- puts " > gen #{gen}, best: #{best[:fitness]}, #{best[:bitstring]}"
70
- break best[:fitness] == num_bits
56
+
57
+ def search(max_gens, num_bits, pop_size, p_crossover, p_mutation)
58
+ population = Array.new(pop_size) do |i|
59
+ {:bitstring => random_bitstring(num_bits)}
60
+ end
61
+ population.each { |c| c[:fitness] = onemax(c[:bitstring]) }
62
+ best = population.sort { |x, y| y[:fitness] <=> x[:fitness] }.first
63
+ max_gens.times do |gen|
64
+ selected = Array.new(pop_size) { |i| binary_tournament(population) }
65
+ children = reproduce(selected, pop_size, p_crossover, p_mutation)
66
+ children.each { |c| c[:fitness] = onemax(c[:bitstring]) }
67
+ children.sort! { |x, y| y[:fitness] <=> x[:fitness] }
68
+ best = children.first if children.first[:fitness] >= best[:fitness]
69
+ population = children
70
+ puts " > gen #{gen}, best: #{best[:fitness]}, #{best[:bitstring]}"
71
+ break best[:fitness] == num_bits
72
+ end
73
+ best
71
74
  end
72
- best
75
+
73
76
  end
74
77
 
75
78
  end
76
-
77
79
  end
@@ -1,78 +1,80 @@
1
- module Neural
1
+ module Algorithmically
2
+ module Neural
2
3
 
3
- class Perceptron
4
+ class Perceptron
4
5
 
5
- def initialize(or_problem, inputs, iterations, learning_rate)
6
- execute(or_problem, inputs, iterations, learning_rate)
7
- end
6
+ def initialize(or_problem, inputs, iterations, learning_rate)
7
+ execute(or_problem, inputs, iterations, learning_rate)
8
+ end
8
9
 
9
- def random_vector(minmax)
10
- Array.new(minmax.size) do |i|
11
- minmax[i][0] + ((minmax[i][1] - minmax[i][0]) * rand())
10
+ def random_vector(minmax)
11
+ Array.new(minmax.size) do |i|
12
+ minmax[i][0] + ((minmax[i][1] - minmax[i][0]) * rand())
13
+ end
12
14
  end
13
- end
14
15
 
15
- def initialize_weights(problem_size)
16
- minmax = Array.new(problem_size + 1) { [-1.0, 1.0] }
17
- random_vector(minmax)
18
- end
16
+ def initialize_weights(problem_size)
17
+ minmax = Array.new(problem_size + 1) { [-1.0, 1.0] }
18
+ random_vector(minmax)
19
+ end
19
20
 
20
- def update_weights(num_inputs, weights, input, out_exp, out_act, l_rate)
21
- num_inputs.times do |i|
22
- weights[i] += l_rate * (out_exp - out_act) * input[i]
21
+ def update_weights(num_inputs, weights, input, out_exp, out_act, l_rate)
22
+ num_inputs.times do |i|
23
+ weights[i] += l_rate * (out_exp - out_act) * input[i]
24
+ end
25
+ weights[num_inputs] += l_rate * (out_exp - out_act) * 1.0
23
26
  end
24
- weights[num_inputs] += l_rate * (out_exp - out_act) * 1.0
25
- end
26
27
 
27
- def activate(weights, vector)
28
- sum = weights[weights.size-1] * 1.0
29
- vector.each_with_index do |input, i|
30
- sum += weights[i] * input
28
+ def activate(weights, vector)
29
+ sum = weights[weights.size-1] * 1.0
30
+ vector.each_with_index do |input, i|
31
+ sum += weights[i] * input
32
+ end
33
+ sum
31
34
  end
32
- sum
33
- end
34
35
 
35
- def transfer(activation)
36
- (activation >= 0) ? 1.0 : 0.0
37
- end
36
+ def transfer(activation)
37
+ (activation >= 0) ? 1.0 : 0.0
38
+ end
38
39
 
39
- def get_output(weights, vector)
40
- activation = activate(weights, vector)
41
- transfer(activation)
42
- end
40
+ def get_output(weights, vector)
41
+ activation = activate(weights, vector)
42
+ transfer(activation)
43
+ end
44
+
45
+ def train_weights(weights, domain, num_inputs, iterations, lrate)
46
+ iterations.times do |epoch|
47
+ error = 0.0
48
+ domain.each do |pattern|
49
+ input = Array.new(num_inputs) { |k| pattern[k].to_f }
50
+ output = get_output(weights, input)
51
+ expected = pattern.last.to_f
52
+ error += (output - expected).abs
53
+ update_weights(num_inputs, weights, input, expected, output, lrate)
54
+ end
55
+ puts "> epoch=#{epoch}, error=#{error}"
56
+ end
57
+ end
43
58
 
44
- def train_weights(weights, domain, num_inputs, iterations, lrate)
45
- iterations.times do |epoch|
46
- error = 0.0
59
+ def test_weights(weights, domain, num_inputs)
60
+ correct = 0
47
61
  domain.each do |pattern|
48
- input = Array.new(num_inputs) { |k| pattern[k].to_f }
49
- output = get_output(weights, input)
50
- expected = pattern.last.to_f
51
- error += (output - expected).abs
52
- update_weights(num_inputs, weights, input, expected, output, lrate)
62
+ input_vector = Array.new(num_inputs) { |k| pattern[k].to_f }
63
+ output = get_output(weights, input_vector)
64
+ correct += 1 if output.round == pattern.last
53
65
  end
54
- puts "> epoch=#{epoch}, error=#{error}"
66
+ puts "Finished test with a score of #{correct}/#{domain.size}"
67
+ correct
55
68
  end
56
- end
57
69
 
58
- def test_weights(weights, domain, num_inputs)
59
- correct = 0
60
- domain.each do |pattern|
61
- input_vector = Array.new(num_inputs) { |k| pattern[k].to_f }
62
- output = get_output(weights, input_vector)
63
- correct += 1 if output.round == pattern.last
70
+ def execute(domain, num_inputs, iterations, learning_rate)
71
+ weights = initialize_weights(num_inputs)
72
+ train_weights(weights, domain, num_inputs, iterations, learning_rate)
73
+ test_weights(weights, domain, num_inputs)
74
+ weights
64
75
  end
65
- puts "Finished test with a score of #{correct}/#{domain.size}"
66
- correct
67
- end
68
76
 
69
- def execute(domain, num_inputs, iterations, learning_rate)
70
- weights = initialize_weights(num_inputs)
71
- train_weights(weights, domain, num_inputs, iterations, learning_rate)
72
- test_weights(weights, domain, num_inputs)
73
- weights
74
77
  end
75
78
 
76
79
  end
77
-
78
80
  end
@@ -1,82 +1,84 @@
1
- module Stochastic
1
+ module Algorithmically
2
+ module Stochastic
2
3
 
3
- class AdaptiveRandomSearch
4
+ class AdaptiveRandomSearch
4
5
 
5
- def initialize(max_iter, bounds, init_factor, s_factor, l_factor, iter_mult, max_no_impr)
6
- problem_size = bounds
7
- @bounds1 = Array.new(problem_size) {|i| [-5, +5]}
8
- @max_iter = max_iter
9
- @init_factor = init_factor
10
- @s_factor = s_factor
11
- @l_factor = l_factor
12
- @iter_mult = iter_mult
13
- @max_no_impr = max_no_impr
14
- @best = search(@max_iter, @bounds1, @init_factor, @s_factor, @l_factor, @iter_mult, @max_no_impr)
15
- puts "Done. Best Solution: c=#{@best[:cost]}, v=#{@best[:vector].inspect}"
16
- end
6
+ def initialize(max_iter, bounds, init_factor, s_factor, l_factor, iter_mult, max_no_impr)
7
+ problem_size = bounds
8
+ @bounds1 = Array.new(problem_size) { |i| [-5, +5] }
9
+ @max_iter = max_iter
10
+ @init_factor = init_factor
11
+ @s_factor = s_factor
12
+ @l_factor = l_factor
13
+ @iter_mult = iter_mult
14
+ @max_no_impr = max_no_impr
15
+ @best = search(@max_iter, @bounds1, @init_factor, @s_factor, @l_factor, @iter_mult, @max_no_impr)
16
+ puts "Done. Best Solution: c=#{@best[:cost]}, v=#{@best[:vector].inspect}"
17
+ end
17
18
 
18
- def objective_function(vector)
19
- vector.inject(0) { |sum, x| sum + (x ** 2.0) }
20
- end
19
+ def objective_function(vector)
20
+ vector.inject(0) { |sum, x| sum + (x ** 2.0) }
21
+ end
21
22
 
22
- def rand_in_bounds(min, max)
23
- min + ((max-min) * rand())
24
- end
23
+ def rand_in_bounds(min, max)
24
+ min + ((max-min) * rand())
25
+ end
25
26
 
26
- def random_vector(minmax)
27
- Array.new(minmax.size) do |i|
28
- rand_in_bounds(minmax[i][0], minmax[i][1])
27
+ def random_vector(minmax)
28
+ Array.new(minmax.size) do |i|
29
+ rand_in_bounds(minmax[i][0], minmax[i][1])
30
+ end
29
31
  end
30
- end
31
32
 
32
- def take_step(minmax, current, step_size)
33
- position = Array.new(current.size)
34
- position.size.times do |i|
35
- min = [minmax[i][0], current[i]-step_size].max
36
- max = [minmax[i][1], current[i]+step_size].min
37
- position[i] = rand_in_bounds(min, max)
33
+ def take_step(minmax, current, step_size)
34
+ position = Array.new(current.size)
35
+ position.size.times do |i|
36
+ min = [minmax[i][0], current[i]-step_size].max
37
+ max = [minmax[i][1], current[i]+step_size].min
38
+ position[i] = rand_in_bounds(min, max)
39
+ end
40
+ position
38
41
  end
39
- position
40
- end
41
42
 
42
- def large_step_size(iter, step_size, s_factor, l_factor, iter_mult)
43
- step_size * l_factor if iter > 0 and iter.modulo(iter_mult) == 0
44
- step_size * s_factor
45
- end
43
+ def large_step_size(iter, step_size, s_factor, l_factor, iter_mult)
44
+ step_size * l_factor if iter > 0 and iter.modulo(iter_mult) == 0
45
+ step_size * s_factor
46
+ end
46
47
 
47
- def take_steps(bounds, current, step_size, big_stepsize)
48
- step, big_step = {}, {}
49
- step[:vector] = take_step(bounds, current[:vector], step_size)
50
- step[:cost] = objective_function(step[:vector])
51
- big_step[:vector] = take_step(bounds, current[:vector], big_stepsize)
52
- big_step[:cost] = objective_function(big_step[:vector])
53
- return step, big_step
54
- end
48
+ def take_steps(bounds, current, step_size, big_stepsize)
49
+ step, big_step = {}, {}
50
+ step[:vector] = take_step(bounds, current[:vector], step_size)
51
+ step[:cost] = objective_function(step[:vector])
52
+ big_step[:vector] = take_step(bounds, current[:vector], big_stepsize)
53
+ big_step[:cost] = objective_function(big_step[:vector])
54
+ return step, big_step
55
+ end
55
56
 
56
- def search(max_iter, bounds, init_factor, s_factor, l_factor, iter_mult, max_no_impr)
57
- step_size = (bounds[0][1]-bounds[0][0]) * init_factor
58
- current, count = {}, 0
59
- current[:vector] = random_vector(bounds)
60
- current[:cost] = objective_function(current[:vector])
61
- max_iter.times do |iter|
62
- big_stepsize = large_step_size(iter, step_size, s_factor, l_factor, iter_mult)
63
- step, big_step = take_steps(bounds, current, step_size, big_stepsize)
64
- if step[:cost] <= current[:cost] or big_step[:cost] <= current[:cost]
65
- if big_step[:cost] <= step[:cost]
66
- step_size, current = big_stepsize, big_step
57
+ def search(max_iter, bounds, init_factor, s_factor, l_factor, iter_mult, max_no_impr)
58
+ step_size = (bounds[0][1]-bounds[0][0]) * init_factor
59
+ current, count = {}, 0
60
+ current[:vector] = random_vector(bounds)
61
+ current[:cost] = objective_function(current[:vector])
62
+ max_iter.times do |iter|
63
+ big_stepsize = large_step_size(iter, step_size, s_factor, l_factor, iter_mult)
64
+ step, big_step = take_steps(bounds, current, step_size, big_stepsize)
65
+ if step[:cost] <= current[:cost] or big_step[:cost] <= current[:cost]
66
+ if big_step[:cost] <= step[:cost]
67
+ step_size, current = big_stepsize, big_step
68
+ else
69
+ current = step
70
+ end
71
+ count = 0
67
72
  else
68
- current = step
73
+ count += 1
74
+ count, step_size = 0, (step_size/s_factor) if count >= max_no_impr
69
75
  end
70
- count = 0
71
- else
72
- count += 1
73
- count, step_size = 0, (step_size/s_factor) if count >= max_no_impr
76
+ puts " > iteration #{(iter+1)}, best=#{current[:cost]}"
74
77
  end
75
- puts " > iteration #{(iter+1)}, best=#{current[:cost]}"
78
+ current
76
79
  end
77
- current
80
+
78
81
  end
79
82
 
80
83
  end
81
-
82
84
  end
@@ -1,107 +1,109 @@
1
- module Stochastic
1
+ module Algorithmically
2
+ module Stochastic
2
3
 
3
- class GuidedLocalSearch
4
+ class GuidedLocalSearch
4
5
 
5
- def initialize(max_iterations, berlin52, max_no_improv, lambda)
6
- @berlin52 = berlin52
7
- @max_iterations = max_iterations
8
- @max_no_improv = max_no_improv
9
- alpha = 0.3
10
- local_search_optima = 12000.0
11
- lambda = alpha * (local_search_optima/berlin52.size.to_f)
12
- @lambda = lambda
13
- best = search(@max_iterations, @berlin52, @max_no_improv, lambda)
14
- puts "Done. Best Solution: c=#{best[:cost]}, v=#{best[:vector].inspect}"
15
- end
16
-
17
- def euc_2d(c1, c2)
18
- Math.sqrt((c1[0] - c2[0])**2.0 + (c1[1] - c2[1])**2.0).round
19
- end
6
+ def initialize(max_iterations, berlin52, max_no_improv, lambda)
7
+ @berlin52 = berlin52
8
+ @max_iterations = max_iterations
9
+ @max_no_improv = max_no_improv
10
+ alpha = 0.3
11
+ local_search_optima = 12000.0
12
+ lambda = alpha * (local_search_optima/berlin52.size.to_f)
13
+ @lambda = lambda
14
+ best = search(@max_iterations, @berlin52, @max_no_improv, lambda)
15
+ puts "Done. Best Solution: c=#{best[:cost]}, v=#{best[:vector].inspect}"
16
+ end
20
17
 
21
- def random_permutation(cities)
22
- perm = Array.new(cities.size) { |i| i }
23
- perm.each_index do |i|
24
- r = rand(perm.size-i) + i
25
- perm[r], perm[i] = perm[i], perm[r]
18
+ def euc_2d(c1, c2)
19
+ Math.sqrt((c1[0] - c2[0])**2.0 + (c1[1] - c2[1])**2.0).round
26
20
  end
27
- perm
28
- end
29
21
 
30
- def stochastic_two_opt(permutation)
31
- perm = Array.new(permutation)
32
- c1, c2 = rand(perm.size), rand(perm.size)
33
- exclude = [c1]
34
- exclude << ((c1==0) ? perm.size-1 : c1-1)
35
- exclude << ((c1==perm.size-1) ? 0 : c1+1)
36
- c2 = rand(perm.size) while exclude.include?(c2)
37
- c1, c2 = c2, c1 if c2 < c1
38
- perm[c1...c2] = perm[c1...c2].reverse
39
- perm
40
- end
22
+ def random_permutation(cities)
23
+ perm = Array.new(cities.size) { |i| i }
24
+ perm.each_index do |i|
25
+ r = rand(perm.size-i) + i
26
+ perm[r], perm[i] = perm[i], perm[r]
27
+ end
28
+ perm
29
+ end
41
30
 
42
- def augmented_cost(permutation, penalties, cities, lambda)
43
- distance, augmented = 0, 0
44
- permutation.each_with_index do |c1, i|
45
- c2 = (i==permutation.size-1) ? permutation[0] : permutation[i+1]
31
+ def stochastic_two_opt(permutation)
32
+ perm = Array.new(permutation)
33
+ c1, c2 = rand(perm.size), rand(perm.size)
34
+ exclude = [c1]
35
+ exclude << ((c1==0) ? perm.size-1 : c1-1)
36
+ exclude << ((c1==perm.size-1) ? 0 : c1+1)
37
+ c2 = rand(perm.size) while exclude.include?(c2)
46
38
  c1, c2 = c2, c1 if c2 < c1
47
- d = euc_2d(cities[c1], cities[c2])
48
- distance += d
49
- augmented += d + (lambda * (penalties[c1][c2]))
39
+ perm[c1...c2] = perm[c1...c2].reverse
40
+ perm
50
41
  end
51
- [distance, augmented]
52
- end
53
42
 
54
- def cost(cand, penalties, cities, lambda)
55
- cost, acost = augmented_cost(cand[:vector], penalties, cities, lambda)
56
- cand[:cost], cand[:aug_cost] = cost, acost
57
- end
43
+ def augmented_cost(permutation, penalties, cities, lambda)
44
+ distance, augmented = 0, 0
45
+ permutation.each_with_index do |c1, i|
46
+ c2 = (i==permutation.size-1) ? permutation[0] : permutation[i+1]
47
+ c1, c2 = c2, c1 if c2 < c1
48
+ d = euc_2d(cities[c1], cities[c2])
49
+ distance += d
50
+ augmented += d + (lambda * (penalties[c1][c2]))
51
+ end
52
+ [distance, augmented]
53
+ end
58
54
 
59
- def local_search(current, cities, penalties, max_no_improv, lambda)
60
- cost(current, penalties, cities, lambda)
61
- count = 0
62
- begin
63
- candidate = {:vector => stochastic_two_opt(current[:vector])}
64
- cost(candidate, penalties, cities, lambda)
65
- count = (candidate[:aug_cost] < current[:aug_cost]) ? 0 : count+1
66
- current = candidate if candidate[:aug_cost] < current[:aug_cost]
67
- end until count >= max_no_improv
68
- current
69
- end
55
+ def cost(cand, penalties, cities, lambda)
56
+ cost, acost = augmented_cost(cand[:vector], penalties, cities, lambda)
57
+ cand[:cost], cand[:aug_cost] = cost, acost
58
+ end
70
59
 
71
- def calculate_feature_utilities(penal, cities, permutation)
72
- utilities = Array.new(permutation.size, 0)
73
- permutation.each_with_index do |c1, i|
74
- c2 = (i==permutation.size-1) ? permutation[0] : permutation[i+1]
75
- c1, c2 = c2, c1 if c2 < c1
76
- utilities[i] = euc_2d(cities[c1], cities[c2]) / (1.0 + penal[c1][c2])
60
+ def local_search(current, cities, penalties, max_no_improv, lambda)
61
+ cost(current, penalties, cities, lambda)
62
+ count = 0
63
+ begin
64
+ candidate = {:vector => stochastic_two_opt(current[:vector])}
65
+ cost(candidate, penalties, cities, lambda)
66
+ count = (candidate[:aug_cost] < current[:aug_cost]) ? 0 : count+1
67
+ current = candidate if candidate[:aug_cost] < current[:aug_cost]
68
+ end until count >= max_no_improv
69
+ current
77
70
  end
78
- utilities
79
- end
80
71
 
81
- def update_penalties!(penalties, cities, permutation, utilities)
82
- max = utilities.max()
83
- permutation.each_with_index do |c1, i|
84
- c2 = (i==permutation.size-1) ? permutation[0] : permutation[i+1]
85
- c1, c2 = c2, c1 if c2 < c1
86
- penalties[c1][c2] += 1 if utilities[i] == max
72
+ def calculate_feature_utilities(penal, cities, permutation)
73
+ utilities = Array.new(permutation.size, 0)
74
+ permutation.each_with_index do |c1, i|
75
+ c2 = (i==permutation.size-1) ? permutation[0] : permutation[i+1]
76
+ c1, c2 = c2, c1 if c2 < c1
77
+ utilities[i] = euc_2d(cities[c1], cities[c2]) / (1.0 + penal[c1][c2])
78
+ end
79
+ utilities
80
+ end
81
+
82
+ def update_penalties!(penalties, cities, permutation, utilities)
83
+ max = utilities.max()
84
+ permutation.each_with_index do |c1, i|
85
+ c2 = (i==permutation.size-1) ? permutation[0] : permutation[i+1]
86
+ c1, c2 = c2, c1 if c2 < c1
87
+ penalties[c1][c2] += 1 if utilities[i] == max
88
+ end
89
+ penalties
87
90
  end
88
- penalties
89
- end
90
91
 
91
- def search(max_iterations, cities, max_no_improv, lambda)
92
- current = {:vector => random_permutation(cities)}
93
- best = nil
94
- penalties = Array.new(cities.size) { Array.new(cities.size, 0) }
95
- max_iterations.times do |iter|
96
- current=local_search(current, cities, penalties, max_no_improv, lambda)
97
- utilities=calculate_feature_utilities(penalties, cities, current[:vector])
98
- update_penalties!(penalties, cities, current[:vector], utilities)
99
- best = current if best.nil? or current[:cost] < best[:cost]
100
- puts " > iter=#{(iter+1)}, best=#{best[:cost]}, aug=#{best[:aug_cost]}"
92
+ def search(max_iterations, cities, max_no_improv, lambda)
93
+ current = {:vector => random_permutation(cities)}
94
+ best = nil
95
+ penalties = Array.new(cities.size) { Array.new(cities.size, 0) }
96
+ max_iterations.times do |iter|
97
+ current=local_search(current, cities, penalties, max_no_improv, lambda)
98
+ utilities=calculate_feature_utilities(penalties, cities, current[:vector])
99
+ update_penalties!(penalties, cities, current[:vector], utilities)
100
+ best = current if best.nil? or current[:cost] < best[:cost]
101
+ puts " > iter=#{(iter+1)}, best=#{best[:cost]}, aug=#{best[:aug_cost]}"
102
+ end
103
+ best
101
104
  end
102
- best
105
+
103
106
  end
104
107
 
105
108
  end
106
-
107
109
  end
@@ -1,42 +1,44 @@
1
- module Stochastic
1
+ module Algorithmically
2
+ module Stochastic
2
3
 
3
- class HillClimbing
4
+ class HillClimbing
4
5
 
5
- def initialize(max_iterations, num_bits)
6
- best = search(max_iterations, num_bits)
7
- puts "Done. Best Solution: c=#{best[:cost]}, v=#{best[:vector].join}"
8
- end
6
+ def initialize(max_iterations, num_bits)
7
+ best = search(max_iterations, num_bits)
8
+ puts "Done. Best Solution: c=#{best[:cost]}, v=#{best[:vector].join}"
9
+ end
9
10
 
10
- def onemax(vector)
11
- vector.inject(0.0) { |sum, v| sum + ((v=="1") ? 1 : 0) }
12
- end
11
+ def onemax(vector)
12
+ vector.inject(0.0) { |sum, v| sum + ((v=="1") ? 1 : 0) }
13
+ end
13
14
 
14
- def random_bitstring(num_bits)
15
- Array.new(num_bits) { |i| (rand<0.5) ? "1" : "0" }
16
- end
15
+ def random_bitstring(num_bits)
16
+ Array.new(num_bits) { |i| (rand<0.5) ? "1" : "0" }
17
+ end
17
18
 
18
- def random_neighbor(bitstring)
19
- mutant = Array.new(bitstring)
20
- pos = rand(bitstring.size)
21
- mutant[pos] = (mutant[pos]=='1') ? '0' : '1'
22
- mutant
23
- end
19
+ def random_neighbor(bitstring)
20
+ mutant = Array.new(bitstring)
21
+ pos = rand(bitstring.size)
22
+ mutant[pos] = (mutant[pos]=='1') ? '0' : '1'
23
+ mutant
24
+ end
24
25
 
25
- def search(max_iterations, num_bits)
26
- candidate = {}
27
- candidate[:vector] = random_bitstring(num_bits)
28
- candidate[:cost] = onemax(candidate[:vector])
29
- max_iterations.times do |iter|
30
- neighbor = {}
31
- neighbor[:vector] = random_neighbor(candidate[:vector])
32
- neighbor[:cost] = onemax(neighbor[:vector])
33
- candidate = neighbor if neighbor[:cost] >= candidate[:cost]
34
- puts " > iteration #{(iter+1)}, best=#{candidate[:cost]}"
35
- break if candidate[:cost] == num_bits
26
+ def search(max_iterations, num_bits)
27
+ candidate = {}
28
+ candidate[:vector] = random_bitstring(num_bits)
29
+ candidate[:cost] = onemax(candidate[:vector])
30
+ max_iterations.times do |iter|
31
+ neighbor = {}
32
+ neighbor[:vector] = random_neighbor(candidate[:vector])
33
+ neighbor[:cost] = onemax(neighbor[:vector])
34
+ candidate = neighbor if neighbor[:cost] >= candidate[:cost]
35
+ puts " > iteration #{(iter+1)}, best=#{candidate[:cost]}"
36
+ break if candidate[:cost] == num_bits
37
+ end
38
+ candidate
36
39
  end
37
- candidate
40
+
38
41
  end
39
42
 
40
43
  end
41
-
42
44
  end
@@ -1,37 +1,39 @@
1
- module Stochastic
1
+ module Algorithmically
2
+ module Stochastic
2
3
 
3
- class RandomSearch
4
+ class RandomSearch
4
5
 
5
- def initialize(size, max_iter)
6
- problem_size = size
7
- search_space = Array.new(problem_size) { |i| [-5, +5] }
8
- maximum_iterations = max_iter
9
- best_solution = self.search(search_space, maximum_iterations)
10
- puts "Done. Best Solution: c = #{best_solution[:cost]}, v = #{best_solution[:vector].inspect}"
11
- end
6
+ def initialize(size, max_iter)
7
+ problem_size = size
8
+ search_space = Array.new(problem_size) { |i| [-5, +5] }
9
+ maximum_iterations = max_iter
10
+ best_solution = self.search(search_space, maximum_iterations)
11
+ puts "Done. Best Solution: c = #{best_solution[:cost]}, v = #{best_solution[:vector].inspect}"
12
+ end
12
13
 
13
- def objective_function(vector)
14
- vector.inject(0) { |sum, x| sum + (x ** 2.0) }
15
- end
14
+ def objective_function(vector)
15
+ vector.inject(0) { |sum, x| sum + (x ** 2.0) }
16
+ end
16
17
 
17
- def random_vector(minmax)
18
- Array.new(minmax.size) do |i|
19
- minmax[i][0] + ((minmax[i][1]) - minmax[i][0] * rand())
18
+ def random_vector(minmax)
19
+ Array.new(minmax.size) do |i|
20
+ minmax[i][0] + ((minmax[i][1]) - minmax[i][0] * rand())
21
+ end
20
22
  end
21
- end
22
23
 
23
- def search(search_space, maximum_iterations)
24
- best_solution = nil
25
- maximum_iterations.times do |iterate|
26
- search_candidate = {}
27
- search_candidate[:vector] = random_vector(search_space)
28
- search_candidate[:cost] = objective_function(search_candidate[:vector])
29
- best_solution = search_candidate if best_solution.nil? or search_candidate[:cost] < best_solution[:cost]
30
- puts " > iteration = #{(iterate + 1)}, best = #{best_solution[:cost]}"
24
+ def search(search_space, maximum_iterations)
25
+ best_solution = nil
26
+ maximum_iterations.times do |iterate|
27
+ search_candidate = {}
28
+ search_candidate[:vector] = random_vector(search_space)
29
+ search_candidate[:cost] = objective_function(search_candidate[:vector])
30
+ best_solution = search_candidate if best_solution.nil? or search_candidate[:cost] < best_solution[:cost]
31
+ puts " > iteration = #{(iterate + 1)}, best = #{best_solution[:cost]}"
32
+ end
33
+ best_solution
31
34
  end
32
- best_solution
35
+
33
36
  end
34
37
 
35
38
  end
36
-
37
39
  end
@@ -1,3 +1,3 @@
1
1
  module Algorithmically
2
- VERSION = '0.1.5'
2
+ VERSION = '0.1.6'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Algorithmically
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - popac