288 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			V
		
	
	
module neuroevolution
 | 
						|
 | 
						|
import rand
 | 
						|
import math
 | 
						|
 | 
						|
fn random_clamped() f64 {
 | 
						|
	return rand.f64() * 2 - 1
 | 
						|
}
 | 
						|
 | 
						|
pub fn activation(a f64) f64 {
 | 
						|
	ap := (-a) / 1
 | 
						|
	return 1 / (1 + math.exp(ap))
 | 
						|
}
 | 
						|
 | 
						|
fn round(a int, b f64) int {
 | 
						|
	return int(math.round(f64(a) * b))
 | 
						|
}
 | 
						|
 | 
						|
struct Neuron {
 | 
						|
mut:
 | 
						|
	value   f64
 | 
						|
	weights []f64
 | 
						|
}
 | 
						|
 | 
						|
fn (mut n Neuron) populate(nb int) {
 | 
						|
	for _ in 0 .. nb {
 | 
						|
		n.weights << random_clamped()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
struct Layer {
 | 
						|
	id int
 | 
						|
mut:
 | 
						|
	neurons []Neuron
 | 
						|
}
 | 
						|
 | 
						|
fn (mut l Layer) populate(nb_neurons int, nb_inputs int) {
 | 
						|
	for _ in 0 .. nb_neurons {
 | 
						|
		mut n := Neuron{}
 | 
						|
		n.populate(nb_inputs)
 | 
						|
		l.neurons << n
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
struct Network {
 | 
						|
mut:
 | 
						|
	layers []Layer
 | 
						|
}
 | 
						|
 | 
						|
fn (mut n Network) populate(network []int) {
 | 
						|
	assert network.len >= 2
 | 
						|
	input := network[0]
 | 
						|
	hiddens := network[1..network.len - 1]
 | 
						|
	output := network[network.len - 1]
 | 
						|
	mut index := 0
 | 
						|
	mut previous_neurons := 0
 | 
						|
	mut input_layer := Layer{
 | 
						|
		id: index
 | 
						|
	}
 | 
						|
	input_layer.populate(input, previous_neurons)
 | 
						|
	n.layers << input_layer
 | 
						|
	previous_neurons = input
 | 
						|
	index++
 | 
						|
	for hidden in hiddens {
 | 
						|
		mut hidden_layer := Layer{
 | 
						|
			id: index
 | 
						|
		}
 | 
						|
		hidden_layer.populate(hidden, previous_neurons)
 | 
						|
		previous_neurons = hidden
 | 
						|
		n.layers << hidden_layer
 | 
						|
		index++
 | 
						|
	}
 | 
						|
	mut output_layer := Layer{
 | 
						|
		id: index
 | 
						|
	}
 | 
						|
	output_layer.populate(output, previous_neurons)
 | 
						|
	n.layers << output_layer
 | 
						|
}
 | 
						|
 | 
						|
fn (n Network) get_save() Save {
 | 
						|
	mut save := Save{}
 | 
						|
	for layer in n.layers {
 | 
						|
		save.neurons << layer.neurons.len
 | 
						|
		for neuron in layer.neurons {
 | 
						|
			for weight in neuron.weights {
 | 
						|
				save.weights << weight
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return save
 | 
						|
}
 | 
						|
 | 
						|
fn (mut n Network) set_save(save Save) {
 | 
						|
	mut previous_neurons := 0
 | 
						|
	mut index := 0
 | 
						|
	mut index_weights := 0
 | 
						|
	n.layers = []
 | 
						|
	for save_neuron in save.neurons {
 | 
						|
		mut layer := Layer{
 | 
						|
			id: index
 | 
						|
		}
 | 
						|
		layer.populate(save_neuron, previous_neurons)
 | 
						|
		for mut neuron in layer.neurons {
 | 
						|
			for i in 0 .. neuron.weights.len {
 | 
						|
				neuron.weights[i] = save.weights[index_weights]
 | 
						|
				index_weights++
 | 
						|
			}
 | 
						|
		}
 | 
						|
		previous_neurons = save_neuron
 | 
						|
		index++
 | 
						|
		n.layers << layer
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
pub fn (mut n Network) compute(inputs []f64) []f64 {
 | 
						|
	assert n.layers.len > 0
 | 
						|
	assert inputs.len == n.layers[0].neurons.len
 | 
						|
	for i, input in inputs {
 | 
						|
		n.layers[0].neurons[i].value = input
 | 
						|
	}
 | 
						|
	mut prev_layer := n.layers[0]
 | 
						|
	for i in 1 .. n.layers.len {
 | 
						|
		for j, neuron in n.layers[i].neurons {
 | 
						|
			mut sum := f64(0)
 | 
						|
			for k, prev_layer_neuron in prev_layer.neurons {
 | 
						|
				sum += prev_layer_neuron.value * neuron.weights[k]
 | 
						|
			}
 | 
						|
			n.layers[i].neurons[j].value = activation(sum)
 | 
						|
		}
 | 
						|
		prev_layer = n.layers[i]
 | 
						|
	}
 | 
						|
	mut outputs := []f64{}
 | 
						|
	mut last_layer := n.layers[n.layers.len - 1]
 | 
						|
	for neuron in last_layer.neurons {
 | 
						|
		outputs << neuron.value
 | 
						|
	}
 | 
						|
	return outputs
 | 
						|
}
 | 
						|
 | 
						|
struct Save {
 | 
						|
mut:
 | 
						|
	neurons []int
 | 
						|
	weights []f64
 | 
						|
}
 | 
						|
 | 
						|
fn (s Save) clone() Save {
 | 
						|
	mut save := Save{}
 | 
						|
	save.neurons << s.neurons
 | 
						|
	save.weights << s.weights
 | 
						|
	return save
 | 
						|
}
 | 
						|
 | 
						|
struct Genome {
 | 
						|
	score   int
 | 
						|
	network Save
 | 
						|
}
 | 
						|
 | 
						|
struct Generation {
 | 
						|
mut:
 | 
						|
	genomes []Genome
 | 
						|
}
 | 
						|
 | 
						|
fn (mut g Generation) add_genome(genome Genome) {
 | 
						|
	mut i := 0
 | 
						|
	for gg in g.genomes {
 | 
						|
		if genome.score > gg.score {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		i++
 | 
						|
	}
 | 
						|
	g.genomes.insert(i, genome)
 | 
						|
}
 | 
						|
 | 
						|
fn (g1 Genome) breed(g2 Genome, nb_child int) []Save {
 | 
						|
	mut datas := []Save{}
 | 
						|
	for _ in 0 .. nb_child {
 | 
						|
		mut data := g1.network.clone()
 | 
						|
		for i, weight in g2.network.weights {
 | 
						|
			if rand.f64() <= 0.5 {
 | 
						|
				data.weights[i] = weight
 | 
						|
			}
 | 
						|
		}
 | 
						|
		for i, _ in data.weights {
 | 
						|
			if rand.f64() <= 0.1 {
 | 
						|
				data.weights[i] += (rand.f64() * 2 - 1) * 0.5
 | 
						|
			}
 | 
						|
		}
 | 
						|
		datas << data
 | 
						|
	}
 | 
						|
	return datas
 | 
						|
}
 | 
						|
 | 
						|
fn (g Generation) next(population int) []Save {
 | 
						|
	mut nexts := []Save{}
 | 
						|
	if population == 0 {
 | 
						|
		return nexts
 | 
						|
	}
 | 
						|
	keep := round(population, 0.2)
 | 
						|
	for i in 0 .. keep {
 | 
						|
		if nexts.len < population {
 | 
						|
			nexts << g.genomes[i].network.clone()
 | 
						|
		}
 | 
						|
	}
 | 
						|
	random := round(population, 0.2)
 | 
						|
	for _ in 0 .. random {
 | 
						|
		if nexts.len < population {
 | 
						|
			mut n := g.genomes[0].network.clone()
 | 
						|
			for k, _ in n.weights {
 | 
						|
				n.weights[k] = random_clamped()
 | 
						|
			}
 | 
						|
			nexts << n
 | 
						|
		}
 | 
						|
	}
 | 
						|
	mut max := 0
 | 
						|
	out: for {
 | 
						|
		for i in 0 .. max {
 | 
						|
			mut childs := g.genomes[i].breed(g.genomes[max], 1)
 | 
						|
			for c in childs {
 | 
						|
				nexts << c
 | 
						|
				if nexts.len >= population {
 | 
						|
					break out
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		max++
 | 
						|
		if max >= g.genomes.len - 1 {
 | 
						|
			max = 0
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nexts
 | 
						|
}
 | 
						|
 | 
						|
pub struct Generations {
 | 
						|
pub:
 | 
						|
	population int
 | 
						|
	network    []int
 | 
						|
mut:
 | 
						|
	generations []Generation
 | 
						|
}
 | 
						|
 | 
						|
fn (mut gs Generations) first() []Save {
 | 
						|
	mut out := []Save{}
 | 
						|
	for _ in 0 .. gs.population {
 | 
						|
		mut nn := Network{}
 | 
						|
		nn.populate(gs.network)
 | 
						|
		out << nn.get_save()
 | 
						|
	}
 | 
						|
	gs.generations << Generation{}
 | 
						|
	return out
 | 
						|
}
 | 
						|
 | 
						|
fn (mut gs Generations) next() []Save {
 | 
						|
	assert gs.generations.len > 0
 | 
						|
	gen := gs.generations[gs.generations.len - 1].next(gs.population)
 | 
						|
	gs.generations << Generation{}
 | 
						|
	return gen
 | 
						|
}
 | 
						|
 | 
						|
fn (mut gs Generations) add_genome(genome Genome) {
 | 
						|
	assert gs.generations.len > 0
 | 
						|
	gs.generations[gs.generations.len - 1].add_genome(genome)
 | 
						|
}
 | 
						|
 | 
						|
fn (mut gs Generations) restart() {
 | 
						|
	gs.generations = []
 | 
						|
}
 | 
						|
 | 
						|
pub fn (mut gs Generations) generate() []Network {
 | 
						|
	saves := if gs.generations.len == 0 { gs.first() } else { gs.next() }
 | 
						|
	mut nns := []Network{}
 | 
						|
	for save in saves {
 | 
						|
		mut nn := Network{}
 | 
						|
		nn.set_save(save)
 | 
						|
		nns << nn
 | 
						|
	}
 | 
						|
	if gs.generations.len >= 2 {
 | 
						|
		gs.generations.delete(0)
 | 
						|
	}
 | 
						|
	return nns
 | 
						|
}
 | 
						|
 | 
						|
pub fn (mut gs Generations) network_score(network Network, score int) {
 | 
						|
	gs.add_genome(Genome{
 | 
						|
		score: score
 | 
						|
		network: network.get_save()
 | 
						|
	})
 | 
						|
}
 |