| 1 | module neuroevolution |
| 2 | |
| 3 | import rand |
| 4 | import math |
| 5 | |
| 6 | fn random_clamped() f64 { |
| 7 | return rand.f64() * 2 - 1 |
| 8 | } |
| 9 | |
| 10 | pub fn activation(a f64) f64 { |
| 11 | ap := (-a) / 1 |
| 12 | return 1 / (1 + math.exp(ap)) |
| 13 | } |
| 14 | |
| 15 | fn round(a int, b f64) int { |
| 16 | return int(math.round(f64(a) * b)) |
| 17 | } |
| 18 | |
| 19 | struct Neuron { |
| 20 | mut: |
| 21 | value f64 |
| 22 | weights []f64 |
| 23 | } |
| 24 | |
| 25 | fn (mut n Neuron) populate(nb int) { |
| 26 | for _ in 0 .. nb { |
| 27 | n.weights << random_clamped() |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | struct Layer { |
| 32 | id int |
| 33 | mut: |
| 34 | neurons []Neuron |
| 35 | } |
| 36 | |
| 37 | fn (mut l Layer) populate(nb_neurons int, nb_inputs int) { |
| 38 | for _ in 0 .. nb_neurons { |
| 39 | mut n := Neuron{} |
| 40 | n.populate(nb_inputs) |
| 41 | l.neurons << n |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | pub struct Network { |
| 46 | mut: |
| 47 | layers []Layer |
| 48 | } |
| 49 | |
| 50 | fn (mut n Network) populate(network []int) { |
| 51 | assert network.len >= 2 |
| 52 | input := network[0] |
| 53 | hiddens := network[1..network.len - 1] |
| 54 | output := network[network.len - 1] |
| 55 | mut index := 0 |
| 56 | mut previous_neurons := 0 |
| 57 | mut input_layer := Layer{ |
| 58 | id: index |
| 59 | } |
| 60 | input_layer.populate(input, previous_neurons) |
| 61 | n.layers << input_layer |
| 62 | previous_neurons = input |
| 63 | index++ |
| 64 | for hidden in hiddens { |
| 65 | mut hidden_layer := Layer{ |
| 66 | id: index |
| 67 | } |
| 68 | hidden_layer.populate(hidden, previous_neurons) |
| 69 | previous_neurons = hidden |
| 70 | n.layers << hidden_layer |
| 71 | index++ |
| 72 | } |
| 73 | mut output_layer := Layer{ |
| 74 | id: index |
| 75 | } |
| 76 | output_layer.populate(output, previous_neurons) |
| 77 | n.layers << output_layer |
| 78 | } |
| 79 | |
| 80 | fn (n Network) get_save() Save { |
| 81 | mut save := Save{} |
| 82 | for layer in n.layers { |
| 83 | save.neurons << layer.neurons.len |
| 84 | for neuron in layer.neurons { |
| 85 | for weight in neuron.weights { |
| 86 | save.weights << weight |
| 87 | } |
| 88 | } |
| 89 | } |
| 90 | return save |
| 91 | } |
| 92 | |
| 93 | fn (mut n Network) set_save(save Save) { |
| 94 | mut previous_neurons := 0 |
| 95 | mut index := 0 |
| 96 | mut index_weights := 0 |
| 97 | n.layers = [] |
| 98 | for save_neuron in save.neurons { |
| 99 | mut layer := Layer{ |
| 100 | id: index |
| 101 | } |
| 102 | layer.populate(save_neuron, previous_neurons) |
| 103 | for mut neuron in layer.neurons { |
| 104 | for i in 0 .. neuron.weights.len { |
| 105 | neuron.weights[i] = save.weights[index_weights] |
| 106 | index_weights++ |
| 107 | } |
| 108 | } |
| 109 | previous_neurons = save_neuron |
| 110 | index++ |
| 111 | n.layers << layer |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | pub fn (mut n Network) compute(inputs []f64) []f64 { |
| 116 | assert n.layers.len > 0 |
| 117 | assert inputs.len == n.layers[0].neurons.len |
| 118 | for i, input in inputs { |
| 119 | n.layers[0].neurons[i].value = input |
| 120 | } |
| 121 | mut prev_layer := n.layers[0] |
| 122 | for i in 1 .. n.layers.len { |
| 123 | for j, neuron in n.layers[i].neurons { |
| 124 | mut sum := f64(0) |
| 125 | for k, prev_layer_neuron in prev_layer.neurons { |
| 126 | sum += prev_layer_neuron.value * neuron.weights[k] |
| 127 | } |
| 128 | n.layers[i].neurons[j].value = activation(sum) |
| 129 | } |
| 130 | prev_layer = n.layers[i] |
| 131 | } |
| 132 | mut outputs := []f64{} |
| 133 | mut last_layer := n.layers[n.layers.len - 1] |
| 134 | for neuron in last_layer.neurons { |
| 135 | outputs << neuron.value |
| 136 | } |
| 137 | return outputs |
| 138 | } |
| 139 | |
| 140 | struct Save { |
| 141 | mut: |
| 142 | neurons []int |
| 143 | weights []f64 |
| 144 | } |
| 145 | |
| 146 | fn (s Save) clone() Save { |
| 147 | mut save := Save{} |
| 148 | save.neurons << s.neurons |
| 149 | save.weights << s.weights |
| 150 | return save |
| 151 | } |
| 152 | |
| 153 | struct Genome { |
| 154 | score int |
| 155 | network Save |
| 156 | } |
| 157 | |
| 158 | struct Generation { |
| 159 | mut: |
| 160 | genomes []Genome |
| 161 | } |
| 162 | |
| 163 | fn (mut g Generation) add_genome(genome Genome) { |
| 164 | mut i := 0 |
| 165 | for gg in g.genomes { |
| 166 | if genome.score > gg.score { |
| 167 | break |
| 168 | } |
| 169 | i++ |
| 170 | } |
| 171 | g.genomes.insert(i, genome) |
| 172 | } |
| 173 | |
| 174 | fn (g1 Genome) breed(g2 Genome, nb_child int) []Save { |
| 175 | mut datas := []Save{} |
| 176 | for _ in 0 .. nb_child { |
| 177 | mut data := g1.network.clone() |
| 178 | for i, weight in g2.network.weights { |
| 179 | if rand.f64() <= 0.5 { |
| 180 | data.weights[i] = weight |
| 181 | } |
| 182 | } |
| 183 | for i, _ in data.weights { |
| 184 | if rand.f64() <= 0.1 { |
| 185 | data.weights[i] += (rand.f64() * 2 - 1) * 0.5 |
| 186 | } |
| 187 | } |
| 188 | datas << data |
| 189 | } |
| 190 | return datas |
| 191 | } |
| 192 | |
| 193 | fn (g Generation) next(population int) []Save { |
| 194 | mut nexts := []Save{} |
| 195 | if population == 0 { |
| 196 | return nexts |
| 197 | } |
| 198 | keep := round(population, 0.2) |
| 199 | for i in 0 .. keep { |
| 200 | if nexts.len < population { |
| 201 | nexts << g.genomes[i].network.clone() |
| 202 | } |
| 203 | } |
| 204 | random := round(population, 0.2) |
| 205 | for _ in 0 .. random { |
| 206 | if nexts.len < population { |
| 207 | mut n := g.genomes[0].network.clone() |
| 208 | for k, _ in n.weights { |
| 209 | n.weights[k] = random_clamped() |
| 210 | } |
| 211 | nexts << n |
| 212 | } |
| 213 | } |
| 214 | mut max := 0 |
| 215 | out: for { |
| 216 | for i in 0 .. max { |
| 217 | mut childs := g.genomes[i].breed(g.genomes[max], 1) |
| 218 | for c in childs { |
| 219 | nexts << c |
| 220 | if nexts.len >= population { |
| 221 | break out |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | max++ |
| 226 | if max >= g.genomes.len - 1 { |
| 227 | max = 0 |
| 228 | } |
| 229 | } |
| 230 | return nexts |
| 231 | } |
| 232 | |
| 233 | pub struct Generations { |
| 234 | pub: |
| 235 | population int |
| 236 | network []int |
| 237 | mut: |
| 238 | generations []Generation |
| 239 | } |
| 240 | |
| 241 | fn (mut gs Generations) first() []Save { |
| 242 | mut out := []Save{} |
| 243 | for _ in 0 .. gs.population { |
| 244 | mut nn := Network{} |
| 245 | nn.populate(gs.network) |
| 246 | out << nn.get_save() |
| 247 | } |
| 248 | gs.generations << Generation{} |
| 249 | return out |
| 250 | } |
| 251 | |
| 252 | fn (mut gs Generations) next() []Save { |
| 253 | assert gs.generations.len > 0 |
| 254 | gen := gs.generations[gs.generations.len - 1].next(gs.population) |
| 255 | gs.generations << Generation{} |
| 256 | return gen |
| 257 | } |
| 258 | |
| 259 | fn (mut gs Generations) add_genome(genome Genome) { |
| 260 | assert gs.generations.len > 0 |
| 261 | gs.generations[gs.generations.len - 1].add_genome(genome) |
| 262 | } |
| 263 | |
| 264 | fn (mut gs Generations) restart() { |
| 265 | gs.generations = [] |
| 266 | } |
| 267 | |
| 268 | pub fn (mut gs Generations) generate() []Network { |
| 269 | saves := if gs.generations.len == 0 { gs.first() } else { gs.next() } |
| 270 | mut nns := []Network{} |
| 271 | for save in saves { |
| 272 | mut nn := Network{} |
| 273 | nn.set_save(save) |
| 274 | nns << nn |
| 275 | } |
| 276 | if gs.generations.len >= 2 { |
| 277 | gs.generations.delete(0) |
| 278 | } |
| 279 | return nns |
| 280 | } |
| 281 | |
| 282 | pub fn (mut gs Generations) network_score(network Network, score int) { |
| 283 | gs.add_genome(Genome{ |
| 284 | score: score |
| 285 | network: network.get_save() |
| 286 | }) |
| 287 | } |
| 288 | |