summaryrefslogtreecommitdiff
path: root/src/genome/genome.js
blob: c288d0223e539f697c32759a12379d1a5f4f5df5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
'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),
  ];
}