github.com/yaricom/goNEAT@v0.0.0-20210507221059-e2110b885482/neat/network/common.go (about)

     1  // The package network provides data holders and utilities to describe Artificial Neural Network
     2  package network
     3  
     4  import (
     5  	"errors"
     6  	"fmt"
     7  	"github.com/yaricom/goNEAT/neat/utils"
     8  	"math"
     9  )
    10  
    11  var (
    12  	// The error to be raised when maximal number of network activation attempts exceeded
    13  	NetErrExceededMaxActivationAttempts = errors.New("maximal network activation attempts exceeded.")
    14  	// The error to be raised when unsupported sensors data array size provided
    15  	NetErrUnsupportedSensorsArraySize = errors.New("the sensors array size is unsupported by network solver")
    16  	// The error to be raised when depth calculation failed due to the loop in network
    17  	NetErrDepthCalculationFailedLoopDetected = errors.New("depth can not be determined for network with loop")
    18  )
    19  
    20  // Defines network solver interface which describes neural network structures with methods to run activation waves through
    21  // them.
    22  type NetworkSolver interface {
    23  	// Propagates activation wave through all network nodes provided number of steps in forward direction.
    24  	// Returns true if activation wave passed from all inputs to outputs.
    25  	ForwardSteps(steps int) (bool, error)
    26  
    27  	// Propagates activation wave through all network nodes provided number of steps by recursion from output nodes
    28  	// Returns true if activation wave passed from all inputs to outputs.
    29  	RecursiveSteps() (bool, error)
    30  
    31  	// Attempts to relax network given amount of steps until giving up. The network considered relaxed when absolute
    32  	// value of the change at any given point is less than maxAllowedSignalDelta during activation waves propagation.
    33  	// If maxAllowedSignalDelta value is less than or equal to 0, the method will return true without checking for relaxation.
    34  	Relax(maxSteps int, maxAllowedSignalDelta float64) (bool, error)
    35  
    36  	// Flushes network state by removing all current activations. Returns true if network flushed successfully or
    37  	// false in case of error.
    38  	Flush() (bool, error)
    39  
    40  	// Set sensors values to the input nodes of the network
    41  	LoadSensors(inputs []float64) error
    42  	// Read output values from the output nodes of the network
    43  	ReadOutputs() []float64
    44  
    45  	// Returns the total number of neural units in the network
    46  	NodeCount() int
    47  	// Returns the total number of links between nodes in the network
    48  	LinkCount() int
    49  }
    50  
    51  // NNodeType defines the type of NNode to create
    52  type NodeType byte
    53  
    54  // Predefined NNode types
    55  const (
    56  	// The neuron type
    57  	NeuronNode NodeType = iota
    58  	// The sensor type
    59  	SensorNode
    60  )
    61  
    62  // Returns human readable NNode type name for given constant value
    63  func NodeTypeName(nType NodeType) string {
    64  	switch nType {
    65  	case NeuronNode:
    66  		return "NEURON"
    67  	case SensorNode:
    68  		return "SENSOR"
    69  	default:
    70  		return "!!! UNKNOWN NODE TYPE !!!"
    71  	}
    72  }
    73  
    74  // NeuronType defines the type of neuron to create
    75  type NodeNeuronType byte
    76  
    77  // These are NNode layer type
    78  const (
    79  	// The node is in hidden layer
    80  	HiddenNeuron NodeNeuronType = iota
    81  	// The node is in input layer
    82  	InputNeuron
    83  	// The node is in output layer
    84  	OutputNeuron
    85  	// The node is bias
    86  	BiasNeuron
    87  )
    88  
    89  // Returns human readable neuron type name for given constant
    90  func NeuronTypeName(nlayer NodeNeuronType) string {
    91  	switch nlayer {
    92  	case HiddenNeuron:
    93  		return "HIDN"
    94  	case InputNeuron:
    95  		return "INPT"
    96  	case OutputNeuron:
    97  		return "OUTP"
    98  	case BiasNeuron:
    99  		return "BIAS"
   100  	default:
   101  		return "!!! UNKNOWN NEURON TYPE !!!"
   102  	}
   103  }
   104  
   105  // Returns neuron node type from its name
   106  func NeuronTypeByName(name string) (NodeNeuronType, error) {
   107  	switch name {
   108  	case "HIDN":
   109  		return HiddenNeuron, nil
   110  	case "INPT":
   111  		return InputNeuron, nil
   112  	case "OUTP":
   113  		return OutputNeuron, nil
   114  	case "BIAS":
   115  		return BiasNeuron, nil
   116  	default:
   117  		return math.MaxInt8, errors.New("Unknown neuron type name: " + name)
   118  	}
   119  }
   120  
   121  // Method to calculate activation for specified neuron node based on it's ActivationType field value.
   122  // Will return error and set -0.0 activation if unsupported activation type requested.
   123  func ActivateNode(node *NNode, a *utils.NodeActivatorsFactory) error {
   124  	out, err := a.ActivateByType(node.ActivationSum, node.Params, node.ActivationType)
   125  	if err == nil {
   126  		node.setActivation(out)
   127  	}
   128  	return err
   129  }
   130  
   131  // Method to activate neuron module presented by provided node. As a result of execution the activation values of all
   132  // input nodes will be processed by corresponding activation function and corresponding activation values of output nodes
   133  // will be set. Will panic if unsupported activation type requested.
   134  func ActivateModule(module *NNode, a *utils.NodeActivatorsFactory) error {
   135  	inputs := make([]float64, len(module.Incoming))
   136  	for i, v := range module.Incoming {
   137  		inputs[i] = v.InNode.GetActiveOut()
   138  	}
   139  
   140  	outputs, err := a.ActivateModuleByType(inputs, module.Params, module.ActivationType)
   141  	if err != nil {
   142  		return err
   143  	}
   144  	if len(outputs) != len(module.Outgoing) {
   145  		return fmt.Errorf(
   146  			"number of output parameters [%d] returned by module activator doesn't match "+
   147  				"the number of output neurons of the module [%d]", len(outputs), len(module.Outgoing))
   148  	}
   149  	// set outputs
   150  	for i, out := range outputs {
   151  		module.Outgoing[i].OutNode.setActivation(out)
   152  		module.Outgoing[i].OutNode.isActive = true // activate output node
   153  	}
   154  	return nil
   155  }