From 70252c2ef37ddf974349fa092dce92782ffd302a Mon Sep 17 00:00:00 2001 From: sanine Date: Mon, 30 Oct 2023 02:14:17 -0500 Subject: add genome creation & mutation trial --- src/genome/genome.js | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) (limited to 'src/genome/genome.js') diff --git a/src/genome/genome.js b/src/genome/genome.js index d2650b5..bc569ff 100644 --- a/src/genome/genome.js +++ b/src/genome/genome.js @@ -1,6 +1,7 @@ 'use strict'; -import { network } from '../mind/topology'; +import { random_choice } from '../util.js'; +import { network } from '../mind/topology.js'; // check if a given genome is valid and compute its size @@ -25,6 +26,7 @@ export function get_size(num_input, num_output, genome) { } +// parse a genome into a useable neural net export function parse_genome(num_input, num_output, genome) { const size = get_size(num_input, num_output, genome); if (size < 0) { @@ -49,6 +51,7 @@ function clamp(value, min, max) { return value; } +// adjust the source input of a gene export function mut_gene_source(n_input, n_internal, n_output, gene, r) { const [source, sink, weight] = gene; @@ -62,6 +65,7 @@ export function mut_gene_source(n_input, n_internal, n_output, gene, r) { } +// adjust the sink target of a gene export function mut_gene_sink(n_input, n_internal, n_output, gene, r) { const [source, sink, weight] = gene; @@ -75,6 +79,9 @@ export function mut_gene_sink(n_input, n_internal, n_output, gene, r) { } +// modify a gene's weight +// only adjusts the weight by performing a weighted average, so as to +// more gently modify the generated net export function mut_gene_weight(weight_max, gene, r) { const [source, sink, weight] = gene; @@ -90,6 +97,9 @@ export function mut_gene_weight(weight_max, gene, r) { } + +// expand the size of the neural net encoded by the genome +// relabels internal indices so that there is one extra internal neuron export function mut_genome_expand( [n_input, n_internal, n_output, genome], r ) { @@ -106,11 +116,16 @@ export function mut_genome_expand( } +// contract the size of the neural net encoded by the genome +// relabels internal indices so that there is one less internal neuron export function mut_genome_contract( [n_input, n_internal, n_output, genome], r ) { const contract_idx = Math.floor(n_internal * r) + n_input; + + // decrement sources on the contract index too, to prevent invalid genomes const new_source = (source) => source >= contract_idx ? source-1 : source; + // decrement sinks only after the contract index const new_sink = (sink) => sink > contract_idx ? sink-1 : sink; const new_genome = genome.map(([source, sink, weight]) => [ @@ -125,6 +140,7 @@ export function mut_genome_contract( } +// append a newly generated gene to the end of the genome export function mut_genome_insert( [n_input, n_internal, n_output, genome], weight_max, @@ -141,6 +157,7 @@ export function mut_genome_insert( } +// delete a gene from the genome export function mut_genome_delete( [n_input, n_internal, n_output, genome], r ) { @@ -148,3 +165,71 @@ export function mut_genome_delete( const new_genome = genome.filter((_, idx) => idx != del_idx); return [n_input, n_internal, n_output, new_genome]; } + + +function mut_gene( + [n_input, n_internal, n_output, genome], + weight_max, r1, r2, r3 +) { + const gene_idx = Math.floor(genome.length * r1); + const mod = random_choice(['source', 'sink', 'weight'], r2); + let new_gene; + if (mod == 'source') { + new_gene = mut_gene_source( + n_input, n_internal, n_output, + genome[gene_idx], + r3 + ); + } else if (mod == 'sink') { + new_gene = mut_gene_sink( + n_input, n_internal, n_output, + genome[gene_idx], + r3 + ); + } else { + new_gene = mut_gene_weight( + weight_max, genome[gene_idx], r3 + ); + } + + const new_genome = genome.map((gene, idx) => { + if (idx == gene_idx) { return new_gene; } + return gene; + }); + + return [ + n_input, n_internal, n_output, new_genome + ]; +} + + +export function mutate_genome(obj, weight_max) { + const mut = random_choice([ + 'gene', 'gene', 'gene', + 'gene', 'gene', 'gene', + 'gene', 'gene', 'gene', + 'insert', 'delete', + 'insert', 'delete', + 'expand', 'contract', + ], Math.random()); + + if (mut == 'gene') { + return mut_gene( + obj, weight_max, + Math.random(), Math.random(), Math.random() + ); + } else if (mut == 'insert') { + return mut_genome_insert( + obj, weight_max, + Math.random(), Math.random(), Math.random() + ); + } else if (mut == 'delete') { + return mut_genome_delete(obj, Math.random()); + } else if (mut == 'expand') { + return mut_genome_expand(obj, Math.random()); + } else if (mut == 'contract') { + return mut_genome_contract(obj, Math.random()); + } else { + throw new Error(`bad mut value: ${mut}`); + } +} -- cgit v1.2.1