ga 0.1.1 → 0.1.2
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 +4 -4
- data/.gitignore +4 -0
- data/Gemfile +1 -0
- data/examples/01bag.rb +3 -1
- data/examples/Makefile +17 -0
- data/examples/robot.rb +52 -163
- data/examples/robot_tester.cpp +150 -0
- data/examples/robot_tester.h +36 -0
- data/examples/test.cpp +35 -0
- data/lib/ga/version.rb +1 -1
- data/lib/ga/zoo.rb +32 -9
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2831b4e765ee161b47cbfd96efa977e635443047
|
4
|
+
data.tar.gz: '09022f90fcf17f9892e576534648b48f49703ab1'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5a0c7db9d6a018b65816060a1da1d9544da8fe3dbc44ef06174797abec42e50e407ecfa1ba115b0763b0cb95ac6812df91ac34d2ecd7ae5a2562db539e4bc34
|
7
|
+
data.tar.gz: 335144415a50aef9a3afa65dfc5e71dbc3e67d0a4bc69592940c43357be95470f60c03706eb985f6dec145c07dc49b546761ca0cc6fd7a2a787170ca26326a46
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/examples/01bag.rb
CHANGED
@@ -82,7 +82,9 @@ Benchmark.bm do |x|
|
|
82
82
|
x.report('a') do
|
83
83
|
puts 'start'
|
84
84
|
100.times do
|
85
|
-
|
85
|
+
ga = Unit.new_ga_zoo
|
86
|
+
ga.elite_policy!
|
87
|
+
units = ga.evolve(20, 100, 0.8, 0.15)
|
86
88
|
unit = units.max
|
87
89
|
print unit.inspect + "\r"
|
88
90
|
r[unit.fitness] ||= 0
|
data/examples/Makefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
test: clean test.o robot_tester.o
|
3
|
+
g++ -o test test.o robot_tester.o
|
4
|
+
./test
|
5
|
+
|
6
|
+
sharedlib: clean robot_tester.o
|
7
|
+
g++ -shared -Wall -o librt.so robot_tester.o
|
8
|
+
|
9
|
+
clean:
|
10
|
+
rm -f *.o *.so test
|
11
|
+
|
12
|
+
robot_tester.o: robot_tester.cpp
|
13
|
+
g++ -Wall -c robot_tester.cpp
|
14
|
+
|
15
|
+
test.o: test.cpp
|
16
|
+
g++ -c test.cpp
|
17
|
+
|
data/examples/robot.rb
CHANGED
@@ -1,81 +1,35 @@
|
|
1
|
-
require 'bundler/setup'
|
2
1
|
require 'ga'
|
3
|
-
|
2
|
+
require 'pry'
|
4
3
|
require 'parallel'
|
4
|
+
require 'ffi'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# 0 empty 1 dust 2 wall
|
10
|
-
# [x][y]
|
11
|
-
def new_map
|
12
|
-
MAP_SIZE.times.map { [0] * MAP_SIZE }
|
13
|
-
end
|
14
|
-
|
15
|
-
def rand_map(map, dust_rate = 0.5)
|
16
|
-
map.each do |cols|
|
17
|
-
cols.length.times {|i| cols[i] = rand() <= dust_rate ? 1 : 0 }
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def show_map(map, bx = nil, by = nil)
|
22
|
-
puts('-' * 20)
|
23
|
-
MAP_SIZE.times do |y|
|
24
|
-
MAP_SIZE.times do |x|
|
25
|
-
if bx == x and by == y then
|
26
|
-
print(map[x][y], '* ')
|
27
|
-
else
|
28
|
-
print(map[x][y], ' ')
|
29
|
-
end
|
30
|
-
end
|
31
|
-
print("\n")
|
32
|
-
end
|
33
|
-
puts('-' * 20)
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
# 0 random move
|
38
|
-
# 9 clear
|
39
|
-
# 1 2 3
|
40
|
-
# 4 5
|
41
|
-
# 6 7 8
|
42
|
-
ACTIONS_DATA = {
|
43
|
-
0 => nil,
|
44
|
-
9 => nil,
|
45
|
-
|
46
|
-
# 1 => [-1, -1],
|
47
|
-
2 => [0, -1],
|
48
|
-
# 3 => [1, -1],
|
49
|
-
|
50
|
-
4 => [-1, 0],
|
51
|
-
# 5 => [1, 0],
|
6
|
+
system 'make sharedlib'
|
52
7
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
8
|
+
# env:
|
9
|
+
# '12001'
|
10
|
+
# 1
|
11
|
+
# 2 3 4
|
12
|
+
# 5
|
57
13
|
|
58
|
-
|
59
|
-
|
14
|
+
# actions:
|
15
|
+
# 1
|
16
|
+
# 2 3
|
17
|
+
# 4
|
18
|
+
# 1 2 3 4 move
|
19
|
+
# 0 rand move
|
20
|
+
# 5 clean
|
21
|
+
ACTIONS = [0, 1, 2, 3, 4, 5]
|
60
22
|
|
61
23
|
class Robot
|
62
24
|
include GA
|
63
25
|
|
64
|
-
# genome
|
65
|
-
#
|
66
26
|
# {env => action}
|
67
|
-
#
|
68
|
-
# env: '10122'
|
69
|
-
# 1
|
70
|
-
# 2 3 4
|
71
|
-
# 5
|
72
|
-
# action:
|
73
|
-
|
74
27
|
attr_accessor :genome, :fitness
|
75
|
-
|
28
|
+
TOTAL_TEST_TIMES = 100
|
76
29
|
|
77
30
|
def self.random_new
|
78
|
-
|
31
|
+
genome = {}
|
32
|
+
self.new(genome)
|
79
33
|
end
|
80
34
|
|
81
35
|
def initialize(genome)
|
@@ -83,37 +37,22 @@ class Robot
|
|
83
37
|
end
|
84
38
|
|
85
39
|
def fitness
|
86
|
-
|
87
|
-
@fitness ||= TOTAL_VALUE_TEST.times.map { tester.test }.reduce(&:+) / TOTAL_VALUE_TEST
|
88
|
-
end
|
89
|
-
|
90
|
-
def <=>(target)
|
91
|
-
fitness <=> target.fitness
|
40
|
+
@fitness ||= RobotTester.test(TOTAL_TEST_TIMES, 200, self)
|
92
41
|
end
|
93
42
|
|
94
43
|
def analyse_env(env)
|
95
|
-
@genome[env] ||=
|
96
|
-
9
|
97
|
-
elsif env == '00000' then
|
98
|
-
0
|
99
|
-
else
|
100
|
-
MOVE_ACTIONS.sample
|
101
|
-
end
|
44
|
+
@genome[env] ||= ACTIONS.sample
|
102
45
|
end
|
103
46
|
|
104
47
|
def cross!(target)
|
105
48
|
all_genome = (genome.keys + target.genome.keys).uniq
|
106
49
|
len = all_genome.length
|
107
|
-
min_robot = [self, target].min
|
108
50
|
|
109
|
-
rand(len).times do
|
51
|
+
(len / 4 + rand(len / 4)).times do
|
110
52
|
gene = all_genome[rand(len)]
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
else
|
115
|
-
genome[gene], target.genome[gene] = target.genome[gene], genome[gene]
|
116
|
-
end
|
53
|
+
genome[gene] ||= ACTIONS.sample
|
54
|
+
target.genome[gene] ||= ACTIONS.sample
|
55
|
+
genome[gene], target.genome[gene] = target.genome[gene], genome[gene]
|
117
56
|
end
|
118
57
|
end
|
119
58
|
|
@@ -121,94 +60,43 @@ class Robot
|
|
121
60
|
all_genome = genome.keys
|
122
61
|
len = all_genome.length
|
123
62
|
|
124
|
-
(rand(len
|
63
|
+
(len / 4 + rand(len / 2)).times do
|
125
64
|
gene = all_genome[rand(len)]
|
126
|
-
genome[gene] = ACTIONS.sample
|
65
|
+
genome[gene] = (ACTIONS - [genome[gene]]).sample
|
127
66
|
end
|
128
67
|
end
|
129
68
|
end
|
130
69
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
def initialize(robot)
|
135
|
-
@map = new_map
|
136
|
-
@robot = robot
|
137
|
-
end
|
70
|
+
module RobotTester
|
71
|
+
extend FFI::Library
|
138
72
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
y = rand(map.length)
|
143
|
-
@total_value = 0
|
144
|
-
|
145
|
-
step.times do
|
146
|
-
env = scan_env(x, y)
|
147
|
-
action = robot.analyse_env(env)
|
148
|
-
rx, ry = execute_action(x, y, action)
|
149
|
-
|
150
|
-
x += rx
|
151
|
-
y += ry
|
152
|
-
|
153
|
-
if x < 0 or y < 0 or x >= MAP_SIZE or y >= MAP_SIZE then
|
154
|
-
x -= rx
|
155
|
-
y -= ry
|
156
|
-
@total_value -= 10
|
157
|
-
elsif map[x][y] == 1
|
158
|
-
@total_value += 1
|
159
|
-
end
|
160
|
-
|
161
|
-
if show then
|
162
|
-
show_map(map, x, y)
|
163
|
-
sleep 0.2
|
164
|
-
end
|
165
|
-
end
|
73
|
+
ffi_lib File.expand_path('../librt.so', __FILE__)
|
74
|
+
callback :analyse_cb, [:string], :int
|
75
|
+
attach_function :robot_test, [:int, :int, :pointer, :pointer, :int, :analyse_cb], :int
|
166
76
|
|
167
|
-
|
168
|
-
|
77
|
+
def self.test(times, step, robot)
|
78
|
+
genome = robot.genome
|
79
|
+
len = genome.length
|
80
|
+
env_pointer = FFI::MemoryPointer.new(:pointer, len)
|
81
|
+
action_pointer = FFI::MemoryPointer.new(:int, len)
|
169
82
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
if map[x][y] == 1 then
|
174
|
-
map[x][y] = 0
|
175
|
-
@total_value += 10
|
176
|
-
else
|
177
|
-
@total_value -= 10
|
178
|
-
end
|
179
|
-
|
180
|
-
[0, 0]
|
181
|
-
when 0 then
|
182
|
-
@total_value -= 1
|
183
|
-
ACTIONS_DATA[MOVE_ACTIONS.sample]
|
184
|
-
else
|
185
|
-
@total_value -= 1
|
186
|
-
ACTIONS_DATA[action]
|
187
|
-
end
|
188
|
-
end
|
83
|
+
eps = genome.keys.map {|k| FFI::MemoryPointer.from_string(k) }
|
84
|
+
env_pointer.write_array_of_pointer eps
|
85
|
+
action_pointer.write_array_of_int genome.values
|
189
86
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
rx = x + sx
|
196
|
-
ry = y + sy
|
197
|
-
|
198
|
-
if rx < 0 || ry < 0 || rx >= MAP_SIZE || ry >= MAP_SIZE then
|
199
|
-
2
|
200
|
-
else
|
201
|
-
map[rx][ry]
|
202
|
-
end
|
203
|
-
end.join
|
87
|
+
robot_test(
|
88
|
+
times, step,
|
89
|
+
env_pointer, action_pointer, len,
|
90
|
+
robot.method(:analyse_env)
|
91
|
+
)
|
204
92
|
end
|
205
93
|
end
|
206
94
|
|
207
|
-
|
208
95
|
ga_zoo = Robot.new_ga_zoo
|
209
96
|
ga_zoo.debug!
|
97
|
+
# ga_zoo.cataclysm(10, 1)
|
210
98
|
|
211
|
-
ga_zoo.before_init_fitness do |units|
|
99
|
+
ga_zoo.before_init_fitness do |units, generation|
|
212
100
|
vs = Parallel.map(units, in_processes: 8) do |unit|
|
213
101
|
[unit.fitness, unit.genome]
|
214
102
|
end
|
@@ -217,13 +105,14 @@ ga_zoo.before_init_fitness do |units|
|
|
217
105
|
end
|
218
106
|
end
|
219
107
|
|
220
|
-
|
108
|
+
srand(Time.now.to_i)
|
109
|
+
robots = ga_zoo.evolve(200, 1000, 0.9, 0.2)
|
221
110
|
robot = robots.max
|
222
111
|
|
223
|
-
RobotTester.new(robot).test(100, true)
|
224
|
-
|
225
112
|
puts "========= result ============="
|
226
113
|
puts "fitness: #{robot.fitness}"
|
227
114
|
puts robot.genome
|
228
|
-
|
115
|
+
puts "score: %i" % RobotTester.test(1, 200, robot)
|
116
|
+
binding.pry
|
117
|
+
puts 'end'
|
229
118
|
|
@@ -0,0 +1,150 @@
|
|
1
|
+
#include "robot_tester.h"
|
2
|
+
|
3
|
+
#include <cstdio>
|
4
|
+
#include <cstdlib>
|
5
|
+
#include <ctime>
|
6
|
+
#include <unistd.h>
|
7
|
+
|
8
|
+
RobotTester::RobotTester(int map_size, env_map* p_em) {
|
9
|
+
size = map_size;
|
10
|
+
p_env_action = p_em;
|
11
|
+
map = new int*[size];
|
12
|
+
x = 0; y = 0;
|
13
|
+
for (int i = 0; i < size; i++) {
|
14
|
+
map[i] = new int[size];
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
RobotTester::~RobotTester() {
|
19
|
+
for (int i = 0; i < size; i++) {
|
20
|
+
delete map[i];
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
int RobotTester::test(int step, analyse_callback cb, bool play = false) {
|
25
|
+
int score = 0;
|
26
|
+
char env[6] = {0, 0, 0, 0, 0, 0};
|
27
|
+
int action;
|
28
|
+
env_map::iterator em_itor;
|
29
|
+
x = 0; y = 0;
|
30
|
+
|
31
|
+
rand_map();
|
32
|
+
|
33
|
+
for (int i = 0; i < step; i++) {
|
34
|
+
scan_env(env);
|
35
|
+
em_itor = p_env_action->find(env);
|
36
|
+
if (em_itor != p_env_action->end()) {
|
37
|
+
action = em_itor->second;
|
38
|
+
} else {
|
39
|
+
action = cb(env);
|
40
|
+
p_env_action->insert(env_map::value_type(env, action));
|
41
|
+
}
|
42
|
+
|
43
|
+
score = score + execute_action(action == 0 ? (rand() % 4 + 1) : action);
|
44
|
+
if (play) {
|
45
|
+
show_map();
|
46
|
+
usleep(100 * 1000);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
return score;
|
51
|
+
}
|
52
|
+
|
53
|
+
void RobotTester::rand_map() {
|
54
|
+
for (int i = 0; i < size; i++) {
|
55
|
+
for (int j = 0; j < size; j++) {
|
56
|
+
map[i][j] = rand() % 2;
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
const int scan_len = 5;
|
62
|
+
const int scan_points[scan_len][2] = {
|
63
|
+
{0, -1},
|
64
|
+
{-1, 0}, {0, 0}, {1, 0},
|
65
|
+
{0, 1}
|
66
|
+
};
|
67
|
+
void RobotTester::scan_env(char* env) {
|
68
|
+
int sx, sy;
|
69
|
+
for (int i = 0; i < scan_len; i++) {
|
70
|
+
sx = x + scan_points[i][0];
|
71
|
+
sy = y + scan_points[i][1];
|
72
|
+
|
73
|
+
if (sx < 0 || sx >= size || sy < 0 || sy >= size) {
|
74
|
+
env[i] = '2';
|
75
|
+
continue;
|
76
|
+
}
|
77
|
+
env[i] = char(map[sx][sy] + 48);
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
void RobotTester::show_map() {
|
82
|
+
for (int i = 0; i < size; i++) {
|
83
|
+
for (int j = 0; j < size; j++) {
|
84
|
+
printf(" %i%c", map[j][i], (x == j and y == i) ? '*' : ' ');
|
85
|
+
}
|
86
|
+
printf("\n");
|
87
|
+
}
|
88
|
+
printf("\n");
|
89
|
+
}
|
90
|
+
|
91
|
+
// 1 2 3 4 move
|
92
|
+
// 5 take
|
93
|
+
// 1
|
94
|
+
// 2 5 3
|
95
|
+
// 4
|
96
|
+
const int actions[5][2] = {
|
97
|
+
{0, 0}, {0, -1}, {-1, 0}, {1, 0}, {0, 1}
|
98
|
+
};
|
99
|
+
int RobotTester::execute_action(int action) {
|
100
|
+
switch(action) {
|
101
|
+
case 5: {
|
102
|
+
if (map[x][y] == 1) {
|
103
|
+
map[x][y] = 0;
|
104
|
+
return 10;
|
105
|
+
} else {
|
106
|
+
return -1;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
case 1:
|
110
|
+
case 2:
|
111
|
+
case 3:
|
112
|
+
case 4: {
|
113
|
+
int mx = x + actions[action][0];
|
114
|
+
int my = y + actions[action][1];
|
115
|
+
if (mx < 0 || mx >= size || my < 0 || my >= size) {
|
116
|
+
return -5;
|
117
|
+
} else {
|
118
|
+
x = mx; y = my;
|
119
|
+
return 0;
|
120
|
+
}
|
121
|
+
}
|
122
|
+
default:
|
123
|
+
printf("Invalid action %i\n", action);
|
124
|
+
throw("Invalid action\n");
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
typedef std::unordered_map<std::string, short> env_map;
|
129
|
+
|
130
|
+
|
131
|
+
extern "C" {
|
132
|
+
int robot_test(int times, int step, char** envs, short* actions, int elen, analyse_callback cb) {
|
133
|
+
srand(time(0));
|
134
|
+
|
135
|
+
env_map emap;
|
136
|
+
for (int i = 0; i < elen; i++) {
|
137
|
+
emap.insert(env_map::value_type(envs[i], actions[i]));
|
138
|
+
}
|
139
|
+
|
140
|
+
RobotTester rt = RobotTester(10, &emap);
|
141
|
+
int total_score = 0;
|
142
|
+
|
143
|
+
for (int i = 0; i < times; i++) {
|
144
|
+
total_score = total_score + rt.test(step, cb, times == 1);
|
145
|
+
}
|
146
|
+
|
147
|
+
return total_score / times;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#ifndef ROBOT_TESTER_H
|
2
|
+
#define ROBOT_TESTER_H
|
3
|
+
|
4
|
+
#include <unordered_map>
|
5
|
+
#include <string>
|
6
|
+
|
7
|
+
typedef int(*analyse_callback)(const char* const);
|
8
|
+
typedef std::unordered_map<std::string, short> env_map;
|
9
|
+
|
10
|
+
class RobotTester {
|
11
|
+
public:
|
12
|
+
RobotTester(int, env_map*);
|
13
|
+
~RobotTester();
|
14
|
+
int test(int, analyse_callback, bool play);
|
15
|
+
|
16
|
+
void rand_map();
|
17
|
+
void show_map();
|
18
|
+
|
19
|
+
private:
|
20
|
+
env_map* p_env_action;
|
21
|
+
int size;
|
22
|
+
int **map;
|
23
|
+
int x;
|
24
|
+
int y;
|
25
|
+
|
26
|
+
void scan_env(char[5]);
|
27
|
+
int execute_action(int);
|
28
|
+
};
|
29
|
+
|
30
|
+
|
31
|
+
extern "C" {
|
32
|
+
int robot_test(int times, int step, char** envs, short* action, int elen, analyse_callback);
|
33
|
+
}
|
34
|
+
|
35
|
+
#endif
|
36
|
+
|
data/examples/test.cpp
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#include "robot_tester.h"
|
2
|
+
|
3
|
+
#include <cstdio>
|
4
|
+
#include <cstdlib>
|
5
|
+
|
6
|
+
#include <unordered_map>
|
7
|
+
#include <string>
|
8
|
+
|
9
|
+
int analyse_env(const char* const env) {
|
10
|
+
return rand() % 6;
|
11
|
+
}
|
12
|
+
|
13
|
+
typedef std::unordered_map<std::string, short> env_hash;
|
14
|
+
|
15
|
+
int main() {
|
16
|
+
env_hash eh;
|
17
|
+
int step = 200;
|
18
|
+
int times = 200;
|
19
|
+
|
20
|
+
printf("'robot_test' avg score: %i\n", robot_test(times, step, NULL, NULL, 0, analyse_env));
|
21
|
+
|
22
|
+
RobotTester rt = RobotTester(10, &eh);
|
23
|
+
int total_score = 0;
|
24
|
+
printf("env_hash size: %i\n", (int)eh.size());
|
25
|
+
|
26
|
+
for (int i = 0; i < times; i++) {
|
27
|
+
total_score = total_score + rt.test(step, analyse_env, false);
|
28
|
+
}
|
29
|
+
|
30
|
+
printf("env_hash size: %i\n", (int)eh.size());
|
31
|
+
printf("'RobotTester#test' avg score: %i\n", total_score / times);
|
32
|
+
|
33
|
+
return 0;
|
34
|
+
}
|
35
|
+
|
data/lib/ga/version.rb
CHANGED
data/lib/ga/zoo.rb
CHANGED
@@ -1,21 +1,27 @@
|
|
1
1
|
module GA
|
2
2
|
class Zoo
|
3
|
-
attr_reader :unit_cls
|
3
|
+
attr_reader :unit_cls, :before_fitness_callback, :after_select_callback
|
4
4
|
|
5
5
|
def initialize(unit_cls)
|
6
6
|
@unit_cls = unit_cls
|
7
7
|
@debug = false
|
8
8
|
@before_fitness_callback = nil
|
9
|
+
@after_select_callback = nil
|
10
|
+
@elite_policy = false
|
11
|
+
@select_sample = 2
|
9
12
|
end
|
10
13
|
|
11
14
|
def evolve(units = 32, generations = 100, crossover_rate = 0.8, mutation_rate = 0.15)
|
12
15
|
units = units.times.map { unit_cls.random_new } if units.is_a?(Fixnum)
|
16
|
+
@start_at = Time.now
|
13
17
|
|
14
18
|
generations.times do |i|
|
15
19
|
@before_fitness_callback.call(units, i + 1) if @before_fitness_callback
|
16
20
|
output_debug_info(units, generations, i + 1) if @debug
|
17
21
|
|
18
22
|
units = select_units(units)
|
23
|
+
@after_select_callback.call(units, i + 1) if @after_select_callback
|
24
|
+
|
19
25
|
cross(units, crossover_rate)
|
20
26
|
mutate(units, mutation_rate)
|
21
27
|
end
|
@@ -27,25 +33,40 @@ module GA
|
|
27
33
|
@debug = true
|
28
34
|
end
|
29
35
|
|
36
|
+
def set_select_sample(val)
|
37
|
+
@select_sample = val
|
38
|
+
end
|
39
|
+
|
40
|
+
def elite_policy!
|
41
|
+
@elite_policy = true
|
42
|
+
end
|
43
|
+
|
30
44
|
def before_init_fitness(&block)
|
31
45
|
@before_fitness_callback = block
|
32
46
|
end
|
33
47
|
|
48
|
+
def after_select(&block)
|
49
|
+
@after_select_callback = block
|
50
|
+
end
|
51
|
+
|
34
52
|
|
35
53
|
private
|
36
54
|
|
37
55
|
def select_units(units)
|
38
56
|
new_units = units.map do
|
39
|
-
ou = units.sample(
|
57
|
+
ou = units.sample(@select_sample).max
|
40
58
|
unit_cls.new(ou.genome).tap {|u| u.fitness = ou.fitness }
|
41
59
|
end
|
42
60
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
61
|
+
if @elite_policy
|
62
|
+
min_index = new_units.index(new_units.min)
|
63
|
+
if min_index != 0 then
|
64
|
+
new_units[min_index], new_units[0] = new_units[0], new_units[min_index]
|
65
|
+
end
|
66
|
+
max_unit = units.max
|
67
|
+
new_units[0] = unit_cls.new(max_unit.genome)
|
47
68
|
end
|
48
|
-
|
69
|
+
|
49
70
|
new_units
|
50
71
|
end
|
51
72
|
|
@@ -53,7 +74,7 @@ module GA
|
|
53
74
|
last_index = nil
|
54
75
|
|
55
76
|
units.each_with_index do |unit, index|
|
56
|
-
next if index == 0
|
77
|
+
next if @elite_policy && index == 0
|
57
78
|
next if rand() >= rate
|
58
79
|
|
59
80
|
if last_index
|
@@ -69,7 +90,7 @@ module GA
|
|
69
90
|
|
70
91
|
def mutate(units, rate)
|
71
92
|
units.each_with_index do |unit, index|
|
72
|
-
next if index == 0
|
93
|
+
next if @elite_policy && index == 0
|
73
94
|
next if rand() >= rate
|
74
95
|
unit.mutate!
|
75
96
|
# recalculate fitness
|
@@ -80,6 +101,7 @@ module GA
|
|
80
101
|
def output_debug_info(units, generations, generation)
|
81
102
|
units.sort!
|
82
103
|
info = [
|
104
|
+
"[#{(Time.now - @start_at).to_f}]",
|
83
105
|
"GA-#{generation}/#{generations} #{units.count}-#{units[-1].genome.length}",
|
84
106
|
' fitness: '
|
85
107
|
]
|
@@ -88,6 +110,7 @@ module GA
|
|
88
110
|
info << units.map(&:fitness).join(', ')
|
89
111
|
else
|
90
112
|
info << "#{units[0..2].map(&:fitness).join(', ')}"
|
113
|
+
info << " ... #{units[units.length / 2].fitness}"
|
91
114
|
info << " ... #{units[-5..-1].map(&:fitness).join(', ')}"
|
92
115
|
end
|
93
116
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ga
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jiangzhi.xie
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -83,7 +83,11 @@ files:
|
|
83
83
|
- bin/console
|
84
84
|
- bin/setup
|
85
85
|
- examples/01bag.rb
|
86
|
+
- examples/Makefile
|
86
87
|
- examples/robot.rb
|
88
|
+
- examples/robot_tester.cpp
|
89
|
+
- examples/robot_tester.h
|
90
|
+
- examples/test.cpp
|
87
91
|
- ga.gemspec
|
88
92
|
- lib/ga.rb
|
89
93
|
- lib/ga/version.rb
|