diff options
author | sanine <sanine.not@pm.me> | 2023-06-11 20:05:14 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2023-06-11 20:05:14 -0500 |
commit | 2fdb91f84f6de8c03dcc9c50c20ea2fa79e255c1 (patch) | |
tree | c1f7b579928cc2b5e4663a1c942c6026cbd5e272 | |
parent | 20bfb89690618936b61ae79fbc8a6f0071b25060 (diff) |
add self-connections
-rw-r--r-- | src/mind/topology.js | 58 | ||||
-rw-r--r-- | src/mind/topology.test.js | 118 |
2 files changed, 146 insertions, 30 deletions
diff --git a/src/mind/topology.js b/src/mind/topology.js index 58e229e..755fe4a 100644 --- a/src/mind/topology.js +++ b/src/mind/topology.js @@ -1,14 +1,60 @@ 'use strict'; -const PointProto = { - +const DEFAULT_WEIGHT_MAX = 4; + + +const graph_proto = { + connect: function(source, sink, weight) { + return network_connect(this, source, sink, weight); + }, }; +export function network(input_count, internal_count, output_count, weight_max = 4) { + const count = input_count + internal_count + output_count; + const n = Object.create(graph_proto); + n.input_count = input_count; + n.output_count = output_count; + n.adjacency = new Array(count).fill([]); + n.weight = []; + return Object.freeze(n); +} + + +function is_input(n, index) { + return index < n.input_count; +} +function is_output(n, index) { + return index >= (n.adjacency.length - n.output_count); +} + -export function Point(layer, index) { - return Object.freeze({ - layer, - index, +function network_connect(n, source, sink, weight) { + if (is_input(n, sink)) { + // inputs cannot be sinks + throw new Error("attempt to use input as sink"); + } + if (is_output(n, source)) { + // outputs cannot be sources + throw new Error("attempt to use output as source"); + } + + const nn = Object.create(graph_proto); + nn.input_count = n.input_count; + nn.output_count = n.output_count; + nn.adjacency = n.adjacency.map((row, i) => { + if (i === source && i === sink) { + // self-loop + return [...row, 2]; + } else if (i === source) { + return [...row, 1]; + } else if (i === sink) { + return [...row, -1]; + } else { + return [...row, 0]; + } }); + nn.weight = [...n.weight, weight]; + + return Object.freeze(nn); } diff --git a/src/mind/topology.test.js b/src/mind/topology.test.js index 421eb17..5aab350 100644 --- a/src/mind/topology.test.js +++ b/src/mind/topology.test.js @@ -1,31 +1,101 @@ 'use strict'; -import { Point } from './topology'; +import { network } from './topology'; -test('Point works correctly', () => { - const p = Point(0, 1); - expect(p.layer).toBe(0); - expect(p.index).toBe(1); - expect(() => p.layer = 5).toThrow(); + +test('basic network functionality', () => { + const n = network(0, 5, 0); + expect(n).toEqual({ + input_count: 0, + output_count: 0, + adjacency: [ [], [], [], [], [] ], + weight: [], + }); + + expect(() => n.adjacency = []).toThrow(); + expect(() => n.weight = []).toThrow(); + + const nn = n.connect(0, 1, -2); + expect(nn).toEqual({ + input_count: 0, + output_count: 0, + adjacency: [ + [ 1 ], + [ -1 ], + [ 0 ], + [ 0 ], + [ 0 ] + ], + weight: [ -2 ], + }); + + expect(() => nn.adjacency = []).toThrow(); + expect(() => nn.weight = []).toThrow(); + + const nnn = nn.connect(2, 4, 3); + expect(nnn).toEqual({ + input_count: 0, + output_count: 0, + adjacency: [ + [ 1, 0 ], + [ -1, 0 ], + [ 0, 1 ], + [ 0, 0 ], + [ 0, -1 ] + ], + weight: [ -2, 3 ], + }); + + expect(() => nnn.adjacency = []).toThrow(); + expect(() => nnn.weight = []).toThrow(); +}); + + +test( +'networks are restricted from sinking to inputs or sourcing from outputs', +() => { + const n = network(2, 2, 2); + + expect(n.connect(1,2,0)).toEqual({ + input_count: 2, + output_count: 2, + adjacency: [ + [ 0 ], + [ 1 ], + [ -1 ], + [ 0 ], + [ 0 ], + [ 0 ], + ], + weight: [ 0 ], + }); + expect(() => n.connect(2, 1, 0)).toThrow(); + + expect(n.connect(3, 4, 2)).toEqual({ + input_count: 2, + output_count: 2, + adjacency: [ + [ 0 ], + [ 0 ], + [ 0 ], + [ 1 ], + [ -1 ], + [ 0 ], + ], + weight: [ 2 ], + }); + expect(() => n.connect(4, 3, 2)).toThrow(); }); -test('Point equality works correctly', () => { - const a00 = Point(0, 0); - const b00 = Point(0, 0); - const a01 = Point(0, 1); - const b01 = Point(0, 1); - const a10 = Point(1, 0); - const b10 = Point(1, 0); - const a11 = Point(1, 1); - const b11 = Point(1, 1); - - expect(a00 == b00).toBeTruthy(); - expect(a01 == b01).toBeTruthy(); - expect(a10 == b10).toBeTruthy(); - expect(a11 == b11).toBeTruthy(); - - expect(a00 == a01).toBeFalsy(); - expect(a00 == a10).toBeFalsy(); - expect(a00 == a11).toBeFalsy(); +test('self-connections work correctly', () => { + const n = network(0, 1, 0).connect(0, 0, 2.0); + expect(n).toEqual({ + input_count: 0, + output_count: 0, + adjacency: [ + [ 2 ], + ], + weight: [ 2 ], + }); }); |