protected override NetworkDefinition<NeuralNode, NeuralConnection> CreateDefinition()
        {
            var networkDef = new NetworkDefinition<NeuralNode, NeuralConnection>();

            int nodeBeginIndex = InputInterfaceLength;
            int nodeEndIndex = nodeBeginIndex + NodeCount - 1;
            int maxConnectionIndex = InputInterfaceLength + NodeCount + OutputInterfaceLength - 1;

            // Nodes:
            for (int idx = nodeBeginIndex; idx <= nodeEndIndex; idx++)
            {
                networkDef.AddNode(idx, NodeFactory.Create());
            }

            // Input:
            for (int iidx = 0; iidx < nodeBeginIndex; iidx++)
            {
                for (int nidx = nodeBeginIndex; nidx <= nodeEndIndex; nidx++)
                {
                    networkDef.AddConnection(new ConnectionIndex(iidx, nidx), ConnectionFactory.Create());
                }
            }

            // Hidden:
            for (int nidx = nodeBeginIndex; nidx <= nodeEndIndex; nidx++)
            {
                for (int oidx = nidx + 1; oidx <= maxConnectionIndex; oidx++)
                {
                    networkDef.AddConnection(new ConnectionIndex(nidx, oidx), ConnectionFactory.Create());
                    if (Recurrent) networkDef.AddConnection(new ConnectionIndex(oidx, nidx), ConnectionFactory.Create());
                }
            }

            // Output:
            for (int idx = nodeEndIndex + 1; idx <= maxConnectionIndex; idx++)
            {
                networkDef.AddNode(idx, CollectorNodeFactory.Create());
                networkDef.AddConnection(new ConnectionIndex(idx, idx + OutputInterfaceLength), new NeuralConnection());
            }

            Debug.Assert(networkDef.MaxNodeIndex == maxConnectionIndex + OutputInterfaceLength);

            return networkDef;
        }
        private NetworkDefinition<NeuralNode, NeuralConnection> Build()
        {
            var networkDef = new NetworkDefinition<NeuralNode, NeuralConnection>();
            
            int currentNodeIndex = InputInterfaceLength;
            var nodeLayerInfos = new Dictionary<int, IntRange>();
            nodeLayerInfos.Add(0, IntRange.CreateExclusive(0, InputInterfaceLength));

            int entryCount = Definition.NodeCount;

            int entryIdx = 0; 
            foreach (var nodeEntry in Definition.NodeEntries)
            {
                // Info
                var currentInfo = IntRange.CreateExclusive(currentNodeIndex, currentNodeIndex + nodeEntry.Node.NodeCount);
                nodeLayerInfos.Add(nodeEntry.Index, currentInfo);
                currentNodeIndex += nodeEntry.Node.NodeCount;

                // Upper
                foreach (var conn in Definition.GetUpperConnections(nodeEntry.Index))
                {
                    IntRange prevInfo;
                    if (!nodeLayerInfos.TryGetValue(conn.Index.UpperNodeIndex, out prevInfo))
                    {
                        throw GetArchitectureBuildingErrorEx("Node layer definition at '" + conn.Index.UpperNodeIndex + "' doesn't exists.");
                    }

                    for (int uidx = prevInfo.MinValue; uidx <= prevInfo.MaxValue; uidx++)
                    {
                        for (int lidx = currentInfo.MinValue; lidx <= currentInfo.MaxValue; lidx++)
                        {
                            networkDef.AddConnection(new ConnectionIndex(uidx, lidx), conn.Connection.ConnectionFactory.Create());
                        }
                    }
                }

                // Nodes
                for (int idx = currentInfo.MinValue; idx <= currentInfo.MaxValue; idx++)
                {
                    networkDef.AddNode(idx, nodeEntry.Node.NodeFactory.Create());
                }

                var selfConnDef = nodeEntry.Node.SelfConnectionDefinition;

                if (selfConnDef != null)
                {
                    for (int uidx = currentInfo.MinValue; uidx < currentInfo.MaxValue; uidx++)
                    {
                        for (int lidx = uidx + 1; lidx <= currentInfo.MaxValue; lidx++)
                        {
                            networkDef.AddConnection(new ConnectionIndex(uidx, lidx), selfConnDef.ConnectionFactory.Create());
                        }
                    }
                }

                // Output:
                if (entryIdx == entryCount - 1)
                {
                    if (currentInfo.Size != OutputInterfaceLength)
                    {
                        throw GetArchitectureBuildingErrorEx("Last node layer output size must be same as OutputInterfaceLength.");
                    }

                    for (int uidx = currentInfo.MinValue; uidx <= currentInfo.MaxValue; uidx++)
                    {
                        int lidx = uidx + OutputInterfaceLength;
                        networkDef.AddConnection(new ConnectionIndex(uidx, lidx), new NeuralConnection());
                    }
                }

                entryIdx++;
            }

            return networkDef;
        }