public void ConnectFast()
 {
     if (!useOnlyWebSockets)
     {
         Log("IRTSession", GameSparksRT.LogLevel.DEBUG, PeerId + ": Creating new fastConnection to " + FastPort);
         //if (fastConnection != null) {
         fastConnection = new FastConnection(hostName, FastPort, this);
         //}
     }
 }
Esempio n. 2
0
 /// <summary>
 /// Takes a connection and a counter and updates the corresponding
 /// FastConnection element in a phenomeVariables array.
 /// </summary>
 private static void AddConnection(ConnectionGene connection,
                                   out FastConnection fastConnectionElement)
 {
     // We need the NEW index for sources and targets, not the
     // original index in genome.
     fastConnectionElement._srcNeuronIdx =
         idToNewIndex[connection.SourceNodeId];
     fastConnectionElement._tgtNeuronIdx =
         idToNewIndex[connection.TargetNodeId];
     fastConnectionElement._weight = connection.Weight;
 }
        /// <summary>
        /// Creates a AcyclicNetwork from an INetworkDefinition.
        /// </summary>
        public static FastAcyclicNetwork CreateFastAcyclicNetwork(INetworkDefinition networkDef)
        {
            Debug.Assert(!CyclicNetworkTest.IsNetworkCyclic(networkDef), "Attempt to decode a cyclic network into a FastAcyclicNetwork.");

            // Determine the depth of each node in the network.
            // Node depths are used to separate the nodes into depth based layers, these layers can then be
            // used to determine the order in which signals are propagated through the network.
            AcyclicNetworkDepthAnalysis depthAnalysis = new AcyclicNetworkDepthAnalysis();
            NetworkDepthInfo            netDepthInfo  = depthAnalysis.CalculateNodeDepths(networkDef);

            // Construct an array of NodeInfo, ordered by node depth.
            // Create/populate NodeInfo array.
            int[]     nodeDepthArr = netDepthInfo._nodeDepthArr;
            INodeList nodeList     = networkDef.NodeList;
            int       nodeCount    = nodeList.Count;

            NodeInfo[] nodeInfoByDepth = new NodeInfo[nodeCount];
            for (int i = 0; i < nodeCount; i++)
            {
                nodeInfoByDepth[i]._nodeId        = nodeList[i].Id;
                nodeInfoByDepth[i]._definitionIdx = i;
                nodeInfoByDepth[i]._nodeDepth     = nodeDepthArr[i];
            }

            // Sort NodeInfo array.
            // We use an IComparer here because an anonymous method is not accepted on the method overload that accepts
            // a sort range, which we use to avoid sorting the input and bias nodes. Sort() performs an unstable sort therefore
            // we must restrict the range of the sort to ensure the input and bias node indexes are unchanged. Restricting the
            // sort to the required range is also more efficient (less items to sort).
            int inputAndBiasCount = networkDef.InputNodeCount + 1;

            Array.Sort(nodeInfoByDepth, inputAndBiasCount, nodeCount - inputAndBiasCount, NodeDepthComparer.__NodeDepthComparer);

            // Array of live node indexes indexed by their index in the original network definition. This allows us to
            // locate the position of input and output nodes in their new positions in the live network data structures.
            int[] newIdxByDefinitionIdx = new int[nodeCount];

            // Dictionary of live node indexes keyed by node ID. This allows us to convert the network definition connection
            // endpoints from node IDs to indexes into the live/runtime network data structures.
            Dictionary <uint, int> newIdxById = new Dictionary <uint, int>(nodeCount);

            // Populate both the lookup array and dictionary.
            for (int i = 0; i < nodeCount; i++)
            {
                NodeInfo nodeInfo = nodeInfoByDepth[i];
                newIdxByDefinitionIdx[nodeInfo._definitionIdx] = i;
                newIdxById.Add(nodeInfo._nodeId, i);
            }

            // Make a copy of the sub-range of newIdxByDefinitionIdx that represents the output nodes.
            int outputCount = networkDef.OutputNodeCount;

            int[] outputNeuronIdxArr = new int[outputCount];
            // Note. 'inputAndBiasCount' holds the index of the first output node.
            Array.Copy(newIdxByDefinitionIdx, inputAndBiasCount, outputNeuronIdxArr, 0, outputCount);

            // Construct arrays with additional 'per node' data/refs (activation functions, activation fn auxiliary data).
            IActivationFunctionLibrary activationFnLibrary = networkDef.ActivationFnLibrary;

            IActivationFunction[] nodeActivationFnArr = new IActivationFunction[nodeCount];
            double[][]            nodeAuxArgsArray    = new double[nodeCount][];
            for (int i = 0; i < nodeCount; i++)
            {
                int definitionIdx = nodeInfoByDepth[i]._definitionIdx;
                nodeActivationFnArr[i] = activationFnLibrary.GetFunction(nodeList[definitionIdx].ActivationFnId);
                nodeAuxArgsArray[i]    = nodeList[definitionIdx].AuxState;
            }


            //=== Create array of FastConnection(s).

            // Loop the connections and lookup the node IDs for each connection's end points using newIdxById.
            IConnectionList connectionList  = networkDef.ConnectionList;
            int             connectionCount = connectionList.Count;

            FastConnection[] fastConnectionArray = new FastConnection[connectionCount];

            for (int i = 0; i < connectionCount; i++)
            {
                INetworkConnection conn = connectionList[i];
                fastConnectionArray[i]._srcNeuronIdx = newIdxById[conn.SourceNodeId];
                fastConnectionArray[i]._tgtNeuronIdx = newIdxById[conn.TargetNodeId];
                fastConnectionArray[i]._weight       = conn.Weight;
            }

            // Sort fastConnectionArray by source node index. This allows us to activate the connections in the
            // order they are present within the network (by depth). We also secondary sort by target index to
            // improve CPU cache coherency of the data (in order accesses that are as close to each other as possible).
            Array.Sort(fastConnectionArray, delegate(FastConnection x, FastConnection y)
            {
                if (x._srcNeuronIdx < y._srcNeuronIdx)
                {
                    return(-1);
                }
                if (x._srcNeuronIdx > y._srcNeuronIdx)
                {
                    return(1);
                }
                // Secondary sort on target index.
                if (x._tgtNeuronIdx < y._tgtNeuronIdx)
                {
                    return(-1);
                }
                if (x._tgtNeuronIdx > y._tgtNeuronIdx)
                {
                    return(1);
                }
                // Connections are equal (this should not actually happen).
                return(0);
            });

            // Create an array of LayerInfo(s). Each LayerInfo contains the index + 1 of both the last node and last
            // connection in that layer.
            // The array is in order of depth, from layer zero (bias and inputs nodes) to the last layer
            // (usually output nodes, but not necessarily if there is a dead end pathway with a high number of hops).
            // Note. There is guaranteed to be at least one connection with a source at a given depth level, this is
            // because for there to be a layer N there must necessarily be a connection from a node in layer N-1
            // to a node in layer N.
            int netDepth = netDepthInfo._networkDepth;

            LayerInfo[] layerInfoArr = new LayerInfo[netDepth];

            // Scanning over nodes can start at inputAndBiasCount instead of zero,
            // because we know that all nodes prior to that index are at depth zero.
            int nodeIdx = inputAndBiasCount;
            int connIdx = 0;

            for (int currDepth = 0; currDepth < netDepth; currDepth++)
            {
                // Scan for last node at the current depth.
                for (; nodeIdx < nodeCount && nodeInfoByDepth[nodeIdx]._nodeDepth == currDepth; nodeIdx++)
                {
                    ;
                }

                // Scan for last connection at the current depth.
                for (; connIdx < fastConnectionArray.Length && nodeInfoByDepth[fastConnectionArray[connIdx]._srcNeuronIdx]._nodeDepth == currDepth; connIdx++)
                {
                    ;
                }

                // Store node and connection end indexes for the layer.
                layerInfoArr[currDepth]._endNodeIdx       = nodeIdx;
                layerInfoArr[currDepth]._endConnectionIdx = connIdx;
            }

            return(new FastAcyclicNetwork(nodeActivationFnArr, nodeAuxArgsArray, fastConnectionArray, layerInfoArr, outputNeuronIdxArr,
                                          nodeCount, networkDef.InputNodeCount, networkDef.OutputNodeCount));
        }
Esempio n. 4
0
        /// <summary>
        /// Create an array of FastConnection(s) representing the connectivity of the provided INetworkDefinition.
        /// </summary>
        private static FastConnection[] CreateFastConnectionArray(INetworkDefinition networkDef)
        {
            // We vary the decode logic depending on the size of the genome. The most CPU intensive aspect of
            // decoding is the conversion of the neuron IDs at connection endpoints into neuron indexes. For small
            // genomes we simply use the BinarySearch() method on NeuronGeneList for each lookup; Each lookup is
            // an operation with O(log n) time complexity. Thus for C connections and N neurons the number of operations
            // to perform all lookups is approximately = 2*C*Log(N)
            //
            // For larger genomes we invest time in building a Dictionary that maps neuron IDs to their indexes, this on the
            // basis that the time invested will be more than recovered in time saved performing lookups; The time complexity
            // of a dictionary lookup is near constant O(1). Thus number of operations is approximately = O(2*C*1) + the time
            // required to build the dictionary which is approximately O(N).
            //
            // Therefore the choice of lookup type is based on which of these two expressions gives the lowest value.
            //
            //      Binary search.      LookupOps = 2 * C * Log2(N) * x
            //      Dictionary Search.  LookupOps = (N * y) + (2 * C * z)
            //
            // Where x, y and z are constants that adjust for the relative speeds of the lookup and dictionary building operations.
            // Note that the actual time required to perform these separate algorithms is actually a far more complex problem, and
            // for modern CPUs exact times cannot be calculated because of large memory caches and superscalar architecture that
            // makes execution times in a real environment effectively non-deterministic. Thus these calculations are a rough
            // guide/heuristic that estimate which algorithm will perform best. The constants can be found experimentally but will
            // tend to vary depending on factors such as CPU and memory architecture, .Net framework version and what other tasks the
            // CPU is currently doing which may affect our utilisation of memory caches.
            // TODO: Experimentally determine reasonably good values for constants x,y and z in some common real world runtime platform.
            IConnectionList connectionList  = networkDef.ConnectionList;
            INodeList       nodeList        = networkDef.NodeList;
            int             connectionCount = connectionList.Count;
            int             nodeCount       = nodeList.Count;

            FastConnection[] fastConnectionArray = new FastConnection[connectionCount];

            if ((2.0 * connectionCount * Math.Log(nodeCount, 2.0)) < ((2.0 * connectionCount) + nodeCount))
            {
                // Binary search requires items to be sorted.
                Debug.Assert(nodeList.IsSorted());

                // Loop the connections and lookup the neuron IDs for each connection's end points using a binary search
                // on nGeneList. This is probably the quickest approach for small numbers of lookups.
                for (int i = 0; i < connectionCount; i++)
                {
                    INetworkConnection conn = connectionList[i];
                    fastConnectionArray[i]._srcNeuronIdx = nodeList.BinarySearch(conn.SourceNodeId);
                    fastConnectionArray[i]._tgtNeuronIdx = nodeList.BinarySearch(conn.TargetNodeId);
                    fastConnectionArray[i]._weight       = conn.Weight;

                    // Check that the correct neuron indexes were found.
                    Debug.Assert(
                        nodeList[fastConnectionArray[i]._srcNeuronIdx].Id == conn.SourceNodeId &&
                        nodeList[fastConnectionArray[i]._tgtNeuronIdx].Id == conn.TargetNodeId);
                }
            }
            else
            {
                // Build dictionary of neuron indexes keyed on neuron innovation ID.
                Dictionary <uint, int> neuronIndexDictionary = new Dictionary <uint, int>(nodeCount);
                for (int i = 0; i < nodeCount; i++)
                {
                    // ENHANCEMENT: Check if neuron innovation ID requires further manipulation to make a good hash code.
                    neuronIndexDictionary.Add(nodeList[i].Id, i);
                }

                // Loop the connections and lookup the neuron IDs for each connection's end points using neuronIndexDictionary.
                // This is probably the quickest approach for large numbers of lookups.
                for (int i = 0; i < connectionCount; i++)
                {
                    INetworkConnection conn = connectionList[i];
                    fastConnectionArray[i]._srcNeuronIdx = neuronIndexDictionary[conn.SourceNodeId];
                    fastConnectionArray[i]._tgtNeuronIdx = neuronIndexDictionary[conn.TargetNodeId];
                    fastConnectionArray[i]._weight       = conn.Weight;

                    // Check that the correct neuron indexes were found.
                    Debug.Assert(
                        nodeList[fastConnectionArray[i]._srcNeuronIdx].Id == conn.SourceNodeId &&
                        nodeList[fastConnectionArray[i]._tgtNeuronIdx].Id == conn.TargetNodeId);
                }
            }

            return(fastConnectionArray);
        }
        private void CheckConnection()
        {
            try {
                if (DateTime.Now > mustConnectBy)
                {
                    if (ConnectState == GameSparksRT.ConnectState.Disconnected)
                    {
                        Log("IRTSession", GameSparksRT.LogLevel.INFO, "Disconnected, trying to connect");

                        ConnectState = GameSparksRT.ConnectState.Connecting;

#if !__WINDOWS__
                        if (useOnlyWebSockets)
                        {
                            ConnectWSReliable();
                        }
                        else
#endif
                        {
                            ConnectReliable();
                        }

                        connectionAttempts++;
                    }
                    else if (ConnectState == GameSparksRT.ConnectState.Connecting)
                    {
                        ConnectState = GameSparksRT.ConnectState.Disconnected;

                        Log("IRTSession", GameSparksRT.LogLevel.INFO, "Not connected in time, retrying");

#if !__WINDOWS__
                        if (useOnlyWebSockets)
                        {
                            if (reliableWSConnection != null)
                            {
                                reliableWSConnection.StopInternal();
                                reliableWSConnection = null;
                            }
                        }
                        else
#endif
                        {
                            if (reliableConnection != null)
                            {
                                reliableConnection.StopInternal();
                                reliableConnection = null;
                            }

                            if (fastConnection != null)
                            {
                                fastConnection.StopInternal();
                                fastConnection = null;
                            }
                        }
                    }
                }
#if __WINDOWS__
#else
            } catch (ThreadAbortException e) {
                Log("IRTSession", GameSparksRT.LogLevel.INFO, e.StackTrace);

                return;
#endif
            } catch (Exception e) {
                //General exception, ignore it
                System.Diagnostics.Debug.WriteLine(e);

                Log("IRTSession", GameSparksRT.LogLevel.ERROR, e.StackTrace);
            }
        }