# For visualizing FreeNetwork instances # NetViewer.tz (c) 2010 Jacob Schrum. # See Simulation.tz for more copyright information @include "Constants.tz". @include "FreeNetwork.tz". @use Mobile. @define LEFT_EDGE -12. @define BOTTOM_EDGE 1485. @define TOP_EDGE 1515. @define RIGHT_EDGE 12. # Node types @define TYPE_INPUT 0. @define TYPE_HIDDEN 1. @define TYPE_OUTPUT 2. # Connection types @define CONNECT_FORWARD 0. @define CONNECT_RECURRENT 1. # Weight styles @define WEIGHT_POS 0. @define WEIGHT_NEG 1. Abstract : NetViewer { + variables: nodes (list). node-shape (object). frozen-node-shape (object). mini-node-shape (object). mini-node-color (vector). node-colors (list). connection-colors (list). weight-styles (list). networks (list). subpop-size (int). number-of-subpops (int). inputs (list). current-subpop (int). current-member (int). + to init: input-node-color (vector). output-node-color (vector). hidden-node-color (vector). forward-connection-color (vector). recurrent-connection-color (vector). pos-weight-style (string). neg-weight-style (string). inputs = (controller get-additional-input-info). # Initialize display properties node-shape = (new Sphere init-with radius 0.3). frozen-node-shape = (new Cube init-with size (0.5,0.5,0.5)). mini-node-shape = (new Sphere init-with radius 0.1). mini-node-color = (0,0,0). input-node-color = (1,0,0). output-node-color = (0,1,0). hidden-node-color = (0,0,1). node-colors = {input-node-color, hidden-node-color, output-node-color}. forward-connection-color = (0,0,0). recurrent-connection-color = (1,1,1). connection-colors = { forward-connection-color, recurrent-connection-color }. pos-weight-style = "----------------". neg-weight-style = "--- --- --- --- ". weight-styles = {pos-weight-style, neg-weight-style}. + to send-brains these brains (list): free networks. networks = brains. number-of-subpops = |networks|. subpop-size = |(networks{0})|. current-subpop = 0. current-member = 0. self draw subpop current-subpop member current-member. + to get-mini-node-shape: return mini-node-shape. + to get-mini-node-color: return mini-node-color. + to get-node-shape: return node-shape. + to get-frozen-node-shape: return frozen-node-shape. + to get-node-color type t (int): return node-colors{t}. + to get-connection-color type t (int): return connection-colors{t}. + to clear-display: free nodes. + to previous: current-member--. if current-member < 0 : { current-subpop--. if current-subpop < 0 : current-subpop = (|networks| - 1). current-member = (|networks{current-subpop}| - 1). } self draw subpop current-subpop member current-member. + to next: current-member++. if current-member >= |(networks{current-subpop})| : { current-member = 0. current-subpop++. current-subpop %= |networks|. } self draw subpop current-subpop member current-member. + to draw subpop s (int) member m (int): self draw net (networks{s}{m}). + to draw net theNet (object): i (int). j (int). node-list (list). lower-left (vector). upper-left (vector). horizontal-space (double). vertical-space (double). height (int). target (int). color-type (int). weight-type (int). weight (double). layer (int). tempString (string). layer-occupants (list). backup (int). horizontal-space-by-layer (list). weight-style (string). name (string). self clear-display. height = (theNet get-length-longest-non-recurrent-path) + 1. for i = 0, i < height, i++ : push 0 onto layer-occupants. vertical-space = (TOP_EDGE - BOTTOM_EDGE + 0.0) / height. lower-left = (LEFT_EDGE,BOTTOM_EDGE,0). upper-left = (LEFT_EDGE,TOP_EDGE,0). node-list = theNet get-node-list. nodes = ( |node-list| ) new VisualNode. for i = 0, i < |nodes|, i++ : { nodes{ i } give-view of self. } horizontal-space = (RIGHT_EDGE - LEFT_EDGE + 0.0) / (theNet get-number-inputs). # Place input nodes for i = 0, i < (theNet get-number-inputs), i++ : { nodes{i} init-with type TYPE_INPUT frozen (theNet node-is-frozen node i). nodes{i} move to (lower-left + (((i + 0.5) * horizontal-space),0,0)). name = inputs{i}{INPUT_SLOT_METHOD}. tempString = inputs{i}{INPUT_SLOT_ARGS}. name = "$name $tempString". nodes{i} add-menu named name for-method "nothing". } # Place hidden nodes for backup = i, i + (theNet get-number-outputs) < |node-list|, i++ : { nodes{i} init-with type TYPE_HIDDEN frozen (theNet node-is-frozen node i). if ((nodes{i} get-layer) == -1) : { layer = 1. nodes{i} assign-layer of layer. } else { layer = nodes{i} get-layer. } # Pass for recurrent connections for j = 0, j < (node-list{i} get-number-of-output-targets), j++ : { target = ((node-list{i} get-target-node at-position j) get-absolute-position). if (target < i) : { nodes{i} assign-layer of max(layer, (nodes{target} get-layer) + 1 ). } } # Pass for forward connections for j = 0, j < (node-list{i} get-number-of-output-targets), j++ : { target = ((node-list{i} get-target-node at-position j) get-absolute-position). if (target > i) : { nodes{target} assign-layer of max( (layer + 1), (nodes{target} get-layer) ). } } } for i = backup, i + (theNet get-number-outputs) < |node-list|, i++ : { layer = (nodes{i} get-layer). layer-occupants{(layer - 1)} = layer-occupants{(layer - 1)} + 1. } # Determine horizontal spacing for each layer horizontal-space-by-layer = {}. for i = 0, i < |layer-occupants|, i++ : { if layer-occupants{i} > 0 : push ((RIGHT_EDGE - LEFT_EDGE + 0.0) / (layer-occupants{i})) onto horizontal-space-by-layer. layer-occupants{i} = 0. } for i = backup, i + (theNet get-number-outputs) < |node-list|, i++ : { layer = (nodes{i} get-layer). nodes{i} move to (lower-left + ((((layer-occupants{(layer - 1)}) + 0.5) * horizontal-space-by-layer{(layer - 1)}),(vertical-space * layer),0)). layer-occupants{(layer - 1)} = layer-occupants{(layer - 1)} + 1. } horizontal-space = (RIGHT_EDGE - LEFT_EDGE + 0.0) / (theNet get-number-outputs). # Place output nodes for j = i, i < |node-list|, i++ : { nodes{i} init-with type TYPE_OUTPUT frozen (theNet node-is-frozen node i). nodes{i} move to (upper-left + ((((i - j) + 0.5) * horizontal-space),0,0)). } # Place connections for i = 0, i < |node-list|, i++ : { tempString = (node-list{i} get-innovation-number). tempString = "Innovation: $tempString". nodes{i} add-menu named tempString for-method "nothing". nodes{i} add-menu named "Index: $i" for-method "nothing". for j = 0, j < (node-list{i} get-number-of-output-targets), j++ : { target = ((node-list{i} get-target-node at-position j) get-absolute-position). weight = (theNet weight-of-connection-between-positions of i and target). if (weight > 0) : weight-type = WEIGHT_POS. else if (weight < 0) : weight-type = WEIGHT_NEG. weight-style = weight-styles{weight-type}. if (weight != 0) : { if i == target : { # Recurrent connection to self nodes{i} make-self-recurrent with-style weight-style. } else if target <= i : { # recurrent connection to other node color-type = CONNECT_RECURRENT. nodes{i} make-recurrent with-style weight-style to (nodes{target}). } else { color-type = CONNECT_FORWARD. nodes{i} add-line to (nodes{target}) with-color (connection-colors{color-type}) with-style weight-style. } } } } } Mobile : VisualNode { + variables: layer (int). mini-nodes (list). recurrent-connections (int). view (object). + to init: layer = -1. mini-nodes = {}. recurrent-connections = 0. + to give-view of v (object): view = v. + to init-with type t (int) frozen bit (int): if bit : { #print "Frozen node". self set-shape to (view get-frozen-node-shape). self set-color to (0,0,0). } else { self set-shape to (view get-node-shape). self set-color to (view get-node-color type t). } + to assign-layer of l (int): layer = l. + to get-layer: return layer. + to nothing: + to make-recurrent with-style s (string) to n (object): push (new MiniNode) onto mini-nodes. mini-nodes{(|mini-nodes| - 1)} give-view of view. mini-nodes{(|mini-nodes| - 1)} set-relative-vector to (1 + recurrent-connections,-1,0). self add-line to mini-nodes{(|mini-nodes| - 1)} with-color (view get-connection-color type CONNECT_RECURRENT) with-style s. mini-nodes{(|mini-nodes| - 1)} add-line to n with-color (view get-connection-color type CONNECT_RECURRENT) with-style s. recurrent-connections++. + to make-self-recurrent with-style s (string): push (new MiniNode) onto mini-nodes. mini-nodes{(|mini-nodes| - 1)} give-view of view. mini-nodes{(|mini-nodes| - 1)} set-relative-vector to (-1,1,0). push (new MiniNode) onto mini-nodes. mini-nodes{(|mini-nodes| - 1)} give-view of view. mini-nodes{(|mini-nodes| - 1)} set-relative-vector to (-1,-1,0). self add-line to mini-nodes{(|mini-nodes| - 2)} with-color (view get-connection-color type CONNECT_RECURRENT) with-style s. mini-nodes{(|mini-nodes| - 2)} add-line to mini-nodes{(|mini-nodes| - 1)} with-color (view get-connection-color type CONNECT_RECURRENT) with-style s. mini-nodes{(|mini-nodes| - 1)} add-line to self with-color (view get-connection-color type CONNECT_RECURRENT) with-style s. + to iterate: i (int). for i = 0, i < |mini-nodes|, i++ : { mini-nodes{i} move to ((self get-location) + (mini-nodes{i} get-relative-vector)). } + to destroy: free mini-nodes. } Mobile : MiniNode { + variables: relative (vector). view (object). + to init: + to give-view of v (object): view = v. self set-shape to (view get-mini-node-shape). self set-color to (view get-mini-node-color). + to set-relative-vector to v (vector): relative = v. + to get-relative-vector: return relative. }