'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]; }