From f9fc4d26ec5fca9ee175c8a6fbcdd0fa36f10947 Mon Sep 17 00:00:00 2001 From: sanine Date: Thu, 16 Nov 2023 14:50:00 -0600 Subject: clear out js files --- src/genome/README.md | 12 -- src/genome/genome.js | 218 ----------------------------------- src/genome/genome.test.js | 282 ---------------------------------------------- src/genome/trial.js | 37 ------ 4 files changed, 549 deletions(-) delete mode 100644 src/genome/README.md delete mode 100644 src/genome/genome.js delete mode 100644 src/genome/genome.test.js delete mode 100644 src/genome/trial.js (limited to 'src/genome') diff --git a/src/genome/README.md b/src/genome/README.md deleted file mode 100644 index 1135ed0..0000000 --- a/src/genome/README.md +++ /dev/null @@ -1,12 +0,0 @@ -src/genome -========== - -Genomes represent the neural network that underlies a creature. They are an array of tuples of the form `[ source, sink, weight ]`, where: - - * `source` is an integer in the range `[0, N - num_outputs)`, representing the index of the source neuron - * `sink` is an integer in the range `[num_inputs, N)`, representing the index of the sink neuron - * `weight` is a floating-point value in the range `[-4, 4]`, representing the weight of the connection - -`num_input` and `num_output` are fixed by the environment (as they are the input senses and output actions of the creature, respectively). -`N` is not fixed, but is instead determined by the maximum index present in the genome. As long as the maximum index is greater than or -equal to `num_input + num_output`, the genome is considered valid. diff --git a/src/genome/genome.js b/src/genome/genome.js deleted file mode 100644 index 20974fc..0000000 --- a/src/genome/genome.js +++ /dev/null @@ -1,218 +0,0 @@ -'use strict'; - -import { random_choice } from '../util.js'; -import { network } from '../mind/topology.js'; - - -// check if a given genome is valid and compute its size -export function validate_genome(genome) { - const { n_input, n_internal, n_output } = genome; - console.log(n_input + n_internal); - return genome.genes.reduce( - (acc, [source, sink, weight]) => acc && ( - (source < n_input+n_internal) && - (sink >= n_input) - ), - true - ); -} - -// parse a genome into a useable neural net -export function parse_genome(genome) { - const { n_input, n_internal, n_output } = genome; - - const n = genome.genes.reduce( - (acc, [source, sink, weight]) => acc.connect(source, sink, weight), - network(n_input, n_internal, n_output) - ); - - return n; -} - - -// --===== mutations =====-- - -function clamp(value, min, max) { - if (value > max) { return max; } - if (value < min) { return min; } - 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; - - const new_source = r < 0.5 ? source-1 : source+1; - - return [ - clamp(new_source, 0, n_input+n_internal-1), - sink, - weight, - ]; -} - - -// 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; - - 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, - ]; -} - - -// 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; - - 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), - ]; -} - - - -// 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(genome, r) { - const expand_index = Math.floor(genome.n_internal * r) + genome.n_input; - const new_genes = genome.genes.map(([source, sink, weight]) => [ - source >= expand_index ? source+1 : source, - sink >= expand_index ? sink+1 : sink, - weight, - ]); - - return { - ...genome, - n_internal: genome.n_internal+1, - genes: new_genes, - }; -} - - -// 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(genome, r) { - const { n_input, n_internal, n_output } = genome; - 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_genes = genome.genes.map(([source, sink, weight]) => [ - new_source(source), - new_sink(sink), - weight, - ]); - - return { - ...genome, - n_internal: n_internal-1, - genes: new_genes, - }; -} - - -// append a newly generated gene to the end of the genome -export function mut_genome_insert(genome, weight_max, r1=Math.random(), r2=Math.random(), r3=Math.random()) { - const { n_input, n_internal, n_output } = genome; - 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 { - ...genome, - genes: [...genome.genes, [source, sink, weight]], - }; -} - - -// delete a gene from the genome -export function mut_genome_delete(genome, r) { - const del_idx = Math.floor(r * genome.genes.length); - const genes = genome.genes.filter((_, idx) => idx != del_idx); - return { ...genome, genes }; -} - - -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}`); - } -} diff --git a/src/genome/genome.test.js b/src/genome/genome.test.js deleted file mode 100644 index bc64e4e..0000000 --- a/src/genome/genome.test.js +++ /dev/null @@ -1,282 +0,0 @@ -'use strict'; - -// genome structure -// { -// genes: gene[] -// n_input, n_internal, n_output -// } - - -import { - validate_genome, - parse_genome, - mut_gene_source, - mut_gene_sink, - mut_gene_weight, - mut_genome_expand, - mut_genome_contract, - mut_genome_insert, - mut_genome_delete, -} from './genome'; - - -test('genome validation', () => { - expect(validate_genome({ - n_input: 0, n_internal: 1, n_output: 0, - genes: [[0, 0, 1.0]], - })).toBe(true); - expect(validate_genome({ - n_input: 2, n_internal: 0, n_output: 1, - genes: [[0, 2, 1]], - })).toBe(true); - expect(validate_genome({ - n_input: 2, n_internal: 0, n_output: 1, - genes: [[2, 0, 1]], - })).toBe(false); - expect(validate_genome({ - n_input: 2, n_internal: 0, n_output: 1, - genes: [[2, 2, 1]], - })).toBe(false); - expect(validate_genome({ - n_input: 2, n_internal: 1, n_output: 1, - genes: [[3, 2, 1]], - })).toBe(false); -}); - - -test('parse a genome into a neural net', () => { - const n = parse_genome({ - n_input: 1, n_internal: 1, n_output: 1, - genes: [ - [0, 1, 1], - [1, 1, 1], - [1, 2, 1] - ] - }); - - expect(n.input_count).toBe(1); - expect(n.output_count).toBe(1); - expect(n.compute([2], [-1])).toEqual([ - [ Math.tanh( Math.tanh( 2-1 ) ) ], - [ Math.tanh( 2-1 ) ], - ]); -}); - - -test('mutate gene source', () => { - const n_input = 3; - const n_internal = 4; - const n_output = 5; - - expect(mut_gene_source( - n_input, n_internal, n_output, - [0, 4, 0], - 0.0 - )).toEqual([0, 4, 0]); - - expect(mut_gene_source( - n_input, n_internal, n_output, - [0, 4, 0], - 1.0 - )).toEqual([1, 4, 0]); - - expect(mut_gene_source( - n_input, n_internal, n_output, - [6, 4, 0], - 0.0 - )).toEqual([5, 4, 0]); - - expect(mut_gene_source( - n_input, n_internal, n_output, - [6, 4, 0], - 1.0 - )).toEqual([6, 4, 0]); -}); - - -test('mutate gene sink', () => { - const n_input = 3; - const n_internal = 4; - const n_output = 5; - - expect(mut_gene_sink( - n_input, n_internal, n_output, - [0, 7, 0], - 0.0 - )).toEqual([0, 7, 0]); - - expect(mut_gene_sink( - n_input, n_internal, n_output, - [0, 7, 0], - 1.0 - )).toEqual([0, 8, 0]); - - expect(mut_gene_sink( - n_input, n_internal, n_output, - [6, 11, 0], - 0.0 - )).toEqual([6, 10, 0]); - - expect(mut_gene_sink( - n_input, n_internal, n_output, - [6, 11, 0], - 1.0 - )).toEqual([6, 11, 0]); -}); - - -test('mutate gene weight', () => { - const weight_max = 4.0; - - expect(mut_gene_weight( - weight_max, [0, 0, 1], 0.0 - )).toEqual([0, 0, (2 - 4)/3]); - - expect(mut_gene_weight( - weight_max, [0, 0, -4], 1.0 - )).toEqual([0, 0, (-8 + 4)/3]); - - expect(mut_gene_weight( - weight_max, [0, 0, 3], 0.5 - )).toEqual([0, 0, (6+0)/3]); -}); - - -test('expand genome', () => { - const n_input = 1; - const n_internal = 3; - const n_output = 1; - - const genome = { - n_input, n_internal, n_output, - genes: [ - [0, 1, 0], - [1, 2, 0], - [2, 3, 0], - [3, 4, 0], - ], - }; - - expect(mut_genome_expand(genome, 0.0)).toEqual({ - n_input, n_internal: n_internal+1, n_output, - genes: [ - [0, 2, 0], - [2, 3, 0], - [3, 4, 0], - [4, 5, 0], - ], - }); - - expect(mut_genome_expand(genome, 0.5)).toEqual({ - n_input, n_internal: n_internal+1, n_output, - genes: [ - [0, 1, 0], - [1, 3, 0], - [3, 4, 0], - [4, 5, 0], - ], - }); - - expect(mut_genome_expand(genome, 0.99)).toEqual({ - n_input, n_internal: n_internal+1, n_output, - genes: [ - [0, 1, 0], - [1, 2, 0], - [2, 4, 0], - [4, 5, 0], - ], - }); -}); - - -test('contract genome', () => { - const n_input = 1; - const n_internal = 3; - const n_output = 1; - - const genome = { - n_input, n_internal, n_output, - genes: [ - [0, 1, 0], - [1, 2, 1], - [2, 3, 2], - [3, 4, 3], - ], - }; - - expect(mut_genome_contract(genome, 0.0)).toEqual({ - n_input, n_internal: n_internal-1, n_output, - genes: [ - [0, 1, 0], - [0, 1, 1], - [1, 2, 2], - [2, 3, 3], - ], - }); - - expect(mut_genome_contract(genome, 0.5)).toEqual({ - n_input, n_internal: n_internal-1, n_output, - genes: [ - [0, 1, 0], - [1, 2, 1], - [1, 2, 2], - [2, 3, 3], - ], - }); - - expect(mut_genome_contract(genome, 0.99)).toEqual({ - n_input, n_internal: n_internal-1, n_output, - genes: [ - [0, 1, 0], - [1, 2, 1], - [2, 3, 2], - [2, 3, 3], - ], - }); -}); - - - -test('insert new genes', () => { - const n_input = 1; - const n_internal = 2; - const n_output = 1; - const weight_max = 4; - - expect(mut_genome_insert({ - n_input, n_internal, n_output, - genes: [] - }, weight_max, 0, 0.5, 0)).toEqual({ - n_input, n_internal, n_output, - genes: [[0, 2, -4]] - }); - - expect(mut_genome_insert({ - n_input, n_internal, n_output, - genes: [[0, 2, -4]] - }, weight_max, 0.99, 0, 1)).toEqual({ - n_input, n_internal, n_output, - genes: [[0, 2, -4], [2, 1, 4]] - }); -}); - - -test('remove genes', () => { - const n_input = 0; - const n_output = 0; - const n_internal = 3; - const genome = { - n_input, n_internal, n_output, - genes: [[0, 1, 0], [1, 2, 0]], - }; - - expect(mut_genome_delete(genome, 0.0)).toEqual({ - n_input, n_internal, n_output, - genes: [[1, 2, 0]], - }); - - expect(mut_genome_delete(genome, 0.99)).toEqual({ - n_input, n_internal, n_output, - genes: [[0, 1, 0]], - }); -}); diff --git a/src/genome/trial.js b/src/genome/trial.js deleted file mode 100644 index 2ce23bf..0000000 --- a/src/genome/trial.js +++ /dev/null @@ -1,37 +0,0 @@ -import { - get_size, - mut_genome_insert, mutate_genome, -} from './genome.js'; - -const recurse = (f, x0, n) => { - if (n == 0) { - return x0; - } else { - return f(recurse(f, x0, n-1)); - } -}; - - -const n_input = 5; -const n_output = 5; - - -const [_1, _2, _3, genome] = recurse( - s => mut_genome_insert( - s, 4, - Math.random(), Math.random(), Math.random() - ), - [n_input, 10, n_output, []], - 20); - - -const n_internal = get_size(n_input, n_output, genome) - n_input - n_output; -console.log([n_input, n_internal, n_output, genome]); - -const mutation = recurse( - s => mutate_genome(s, 4), - [n_input, n_internal, n_output, genome], - 40 -); - -console.log(mutation); -- cgit v1.2.1