/// <summary>
        /// Constructs a AcyclicNeuralNet with the provided neural net definition parameters.
        /// </summary>
        /// <param name="digraph">Network structure definition</param>
        /// <param name="weightArr">Connection weights array.</param>
        /// <param name="activationFn">Node activation function.</param>
        public NeuralNetAcyclic(
            DirectedGraphAcyclic digraph,
            double[] weightArr,
            VecFnSegment <double> activationFn)
        {
            // Store refs to network structure data.
            _srcIdArr     = digraph.ConnectionIdArrays._sourceIdArr;
            _tgtIdArr     = digraph.ConnectionIdArrays._targetIdArr;
            _weightArr    = weightArr;
            _layerInfoArr = digraph.LayerArray;

            // Store network activation function.
            _activationFn = activationFn;

            // Store input/output node counts.
            _inputCount  = digraph.InputCount;
            _outputCount = digraph.OutputCount;

            // Create working array for node activation signals.
            _activationArr = new double[digraph.TotalNodeCount];

            // Wrap a sub-range of the _activationArr that holds the activation values for the input nodes.
            this.InputVector = new VectorSegment <double>(_activationArr, 0, _inputCount);

            // Wrap the output nodes. Nodes have been sorted by depth within the network therefore the output
            // nodes can no longer be guaranteed to be in a contiguous segment at a fixed location. As such their
            // positions are indicated by outputNodeIdxArr, and so we package up this array with the node signal
            // array to abstract away the indirection described by outputNodeIdxArr.
            this.OutputVector = new MappingVector <double>(_activationArr, digraph.OutputNodeIdxArr);
        }
Exemplo n.º 2
0
    /// <summary>
    /// Constructs a AcyclicNeuralNet with the provided neural net definition parameters.
    /// </summary>
    /// <param name="digraph">Network structure definition.</param>
    /// <param name="weightArr">Connection weights array.</param>
    /// <param name="activationFn">Node activation function.</param>
    public NeuralNetAcyclicSafe(
        DirectedGraphAcyclic digraph,
        double[] weightArr,
        VecFn <double> activationFn)
    {
        Debug.Assert(digraph.ConnectionIds.GetSourceIdSpan().Length == weightArr.Length);

        // Store refs to network structure data.
        _connIds      = digraph.ConnectionIds;
        _weightArr    = weightArr;
        _layerInfoArr = digraph.LayerArray;

        // Store network activation function.
        _activationFn = activationFn;

        // Store input/output node counts.
        _inputCount  = digraph.InputCount;
        _outputCount = digraph.OutputCount;

        // Create working array for node activation signals.
        _activationArr = new double[digraph.TotalNodeCount];

        // Map the inputs vector to the corresponding segment of node activation values.
        this.Inputs = new Memory <double>(_activationArr, 0, _inputCount);

        // Get an array to act a as a contiguous run of output signals.
        _outputArr   = new double[_outputCount];
        this.Outputs = _outputArr;

        // Store the indexes into _activationArr that give the output signals.
        _outputNodeIdxArr = digraph.OutputNodeIdxArr;
    }
Exemplo n.º 3
0
        /// <summary>
        /// Create a NeatGenome with the given meta data, connection genes and supplementary data.
        /// </summary>
        /// <param name="id">Genome ID.</param>
        /// <param name="birthGeneration">Birth generation.</param>
        /// <param name="connGenes">Connection genes.</param>
        /// <param name="hiddenNodeIdArr">An array of the hidden node IDs in the genome, in ascending order.</param>
        /// <returns>A new NeatGenome instance.</returns>
        public NeatGenome <T> Create(
            int id, int birthGeneration,
            ConnectionGenes <T> connGenes,
            int[] hiddenNodeIdArr)
        {
            int inputCount = _metaNeatGenome.InputNodeCount;

            // Create a mapping from node IDs to node indexes.
            Dictionary <int, int> nodeIdxById = BuildNodeIndexById(hiddenNodeIdArr);

            // Create a DictionaryNodeIdMap.
            DictionaryNodeIdMap nodeIndexByIdMap = new DictionaryNodeIdMap(inputCount, nodeIdxById);

            // Create a digraph from the genome.
            DirectedGraph digraph = NeatGenomeBuilderUtils.CreateDirectedGraph(
                _metaNeatGenome, connGenes, nodeIndexByIdMap);

            // Calc the depth of each node in the digraph.
            GraphDepthInfo depthInfo = _graphDepthAnalysis.CalculateNodeDepths(digraph);

            // Create a weighted acyclic digraph.
            // Note. This also outputs connectionIndexMap. For each connection in the acyclic graph this gives
            // the index of the same connection in the genome; this is because connections are re-ordered based
            // on node depth in the acyclic graph.
            DirectedGraphAcyclic acyclicDigraph = DirectedGraphAcyclicBuilderUtils.CreateDirectedGraphAcyclic(
                digraph,
                depthInfo,
                out int[] newIdByOldId,
                out int[] connectionIndexMap,
                ref _timesortWorkArr,
                ref _timesortWorkVArr);

            // TODO: Write unit tests to cover this!
            // Update nodeIdxById with the new depth based node index allocations.
            // Notes.
            // The current nodeIndexByIdMap maps node IDs (also know as innovation IDs in NEAT) to a compact
            // ID space in which any gaps have been removed, i.e. a compacted set of IDs that can be used as indexes,
            // i.e. if there are N nodes in total then the highest node ID will be N-1.
            //
            // Here we map the new compact IDs to an alternative ID space that is also compact, but ensures that nodeIDs
            // reflect the depth of a node in the acyclic graph.
            UpdateNodeIndexById(nodeIdxById, hiddenNodeIdArr, newIdByOldId);

            // Create the neat genome.
            return(new NeatGenome <T>(
                       _metaNeatGenome, id, birthGeneration,
                       connGenes,
                       hiddenNodeIdArr,
                       nodeIndexByIdMap,
                       acyclicDigraph,
                       connectionIndexMap));
        }
Exemplo n.º 4
0
    /// <summary>
    /// Create an array that gives the node layer for each node, keyed by node index.
    /// </summary>
    /// <param name="digraphAcyclic">The directed acyclic graph.</param>
    /// <returns>A new integer array.</returns>
    private static int[] BuildNodeLayerByIdx_Acyclic(DirectedGraphAcyclic digraphAcyclic)
    {
        // Alloc the array, and populate with the already determined node depth values as represented
        // by the layer info provided by DirectedGraphAcyclic.
        int nodeCount = digraphAcyclic.TotalNodeCount;

        int[] nodeLayerByIdx = new int[nodeCount];

        // Use a restricted scope for the loop variables.
        {
            // The first layer is layer 1; layer zero will be used later to represent input nodes only.
            int layerIdx = 1;
            int nodeIdx  = 0;
            foreach (LayerInfo layerInfo in digraphAcyclic.LayerArray)
            {
                for (; nodeIdx < layerInfo.EndNodeIdx; nodeIdx++)
                {
                    nodeLayerByIdx[nodeIdx] = layerIdx;
                }

                layerIdx++;
            }
        }

        // Assign input nodes to their own layer (layer zero).
        for (int i = 0; i < digraphAcyclic.InputCount; i++)
        {
            nodeLayerByIdx[i] = 0;
        }

        // Assign output nodes to their own layer.
        int outputLayerIdx = digraphAcyclic.LayerArray.Length + 1;

        foreach (int outputNodeIdx in digraphAcyclic.OutputNodeIdxArr)
        {
            nodeLayerByIdx[outputNodeIdx] = outputLayerIdx;
        }

        // Remove empty layers (if any), by adjusting the depth values in nodeLayerByIdx.
        RemoveEmptyLayers(nodeLayerByIdx, outputLayerIdx + 1);

        // Return the constructed node layer lookup table.
        return(nodeLayerByIdx);
    }
Exemplo n.º 5
0
    /// <summary>
    /// Constructs a AcyclicNeuralNet with the provided neural net definition parameters.
    /// </summary>
    /// <param name="digraph">Network structure definition.</param>
    /// <param name="weightArr">Connection weights array.</param>
    /// <param name="activationFn">Node activation function.</param>
    public NeuralNetAcyclic(
        DirectedGraphAcyclic digraph,
        double[] weightArr,
        VecFn <double> activationFn)
    {
        Debug.Assert(digraph.ConnectionIds.GetSourceIdSpan().Length == weightArr.Length);

        // Store refs to network structure data.
        _connIds      = digraph.ConnectionIds;
        _weightArr    = weightArr;
        _layerInfoArr = digraph.LayerArray;

        // Store network activation function.
        _activationFn = activationFn;

        // Store input/output node counts.
        _inputCount     = digraph.InputCount;
        _outputCount    = digraph.OutputCount;
        _totalNodeCount = digraph.TotalNodeCount;

        // Get a working array for node activations signals and a separate output signal segment on the end.
        // And map the memory segments onto the array.
        _workingArr = ArrayPool <double> .Shared.Rent(_totalNodeCount + _outputCount);

        _activationMem = _workingArr.AsMemory(0, _totalNodeCount);
        _outputMem     = _workingArr.AsMemory(_totalNodeCount, _outputCount);

        // Map the inputs vector to the corresponding segment of node activation values.
        this.Inputs = _activationMem.Slice(0, _inputCount);

        // Use the already defined outputs memory segment.
        this.Outputs = _outputMem;

        // Store the indexes into _activationArr that give the output signals.
        _outputNodeIdxArr = digraph.OutputNodeIdxArr;
    }