1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
'use strict';
import { network } from '../mind/topology';
// check if a given genome is valid and compute its size
export function get_size(num_input, num_output, genome) {
const [ max_index, max_weight ] = genome.reduce(
([max_index, max_weight ], [ source, sink, weight]) => [
Math.max(max_index, source, sink),
Math.max(max_weight, Math.abs(weight)),
],
[ 0, 0 ]
);
if (max_index < num_input + num_output - 1) {
return -1;
}
else if (max_weight > 4.0) {
return -1;
}
else {
return max_index + 1;
}
}
export function parse_genome(num_input, num_output, genome) {
const size = get_size(num_input, num_output, genome);
if (size < 0) {
// bad genome
throw new Error('invalid genome sequence!');
}
const n = genome.reduce(
(acc, [source, sink, weight]) => acc.connect(source, sink, weight),
network(num_input, size-num_input-num_output, num_output)
);
return n;
}
// --===== mutations =====--
function clamp(value, min, max) {
if (value > max) { return max; }
if (value < min) { return min; }
return value;
}
export function mut_gene_source(n_input, n_internal, n_output, gene, r) {
const [source, sink, weight] = gene;
const new_source = r < 0.5 ? source-1 : source+1;
return [
clamp(new_source, 0, n_input+n_internal-1),
sink,
weight,
];
}
export function mut_gene_sink(n_input, n_internal, n_output, gene, r) {
const [source, sink, weight] = gene;
const new_sink = r < 0.5 ? sink-1 : sink+1;
return [
source,
clamp(new_sink, n_input+n_internal, n_input+n_internal+n_output-1),
weight,
];
}
export function mut_gene_weight(weight_max, gene, r) {
const [source, sink, weight] = gene;
const rr = (2*r)-1;
const move = weight_max * rr;
const new_weight = (2*weight + move)/3;
return [
source,
sink,
clamp(new_weight, -weight_max, weight_max),
];
}
export function mut_genome_expand(
[n_input, n_internal, n_output, genome], r
) {
const expand_index = Math.floor(n_internal * r) + n_input;
const new_genome = genome.map(([source, sink, weight]) => [
source >= expand_index ? source+1 : source,
sink >= expand_index ? sink+1 : sink,
weight,
]);
return [
n_input, n_internal+1, n_output, new_genome,
];
}
export function mut_genome_insert(
[n_input, n_internal, n_output, genome],
weight_max,
r1, r2, r3
) {
const source = Math.floor((n_input + n_internal) * r1);
const sink = Math.floor((n_internal + n_output) * r2) + n_input;
const weight = weight_max * ((2*r3)-1);
return [
n_input, n_internal, n_output,
[...genome, [source, sink, weight]],
];
}
export function mut_genome_delete(
[n_input, n_internal, n_output, genome], r
) {
const del_idx = Math.floor(r * genome.length);
const new_genome = genome.filter((_, idx) => idx != del_idx);
return [n_input, n_internal, n_output, new_genome];
}
|