Represents a connection in a graph.
Example #1
0
        private void PaintConnection(GraphConnection con, PaintState state)
        {
            Point srcPos = ModelToViewport(con.SourceNode.Position, state);
            Point tgtPos = ModelToViewport(con.TargetNode.Position, state);

            // Connections leave from the base of the source node and enter the top of the target node.
            // Adjust end points to make them neatly terminate just underneath the edge of the endpoint nodes.
            srcPos.Y += (int)(state._nodeDiameterHalf * 0.9f);
            tgtPos.Y -= (int)(state._nodeDiameterHalf * 0.9f);

            // Is any part of the connection within the viewport area?
            if (!IsPointWithinViewport(srcPos, state) && !IsPointWithinViewport(tgtPos, state))
            {   // Skip connection. It's outside the viewport area.
                return;
            }

            // Create a pen for painting the connection.
            // Width is related to connection strength/magnitude.
            float width = (float)(con.Weight < 0.0 ? -Math.Log10(1.0 - con.Weight) : Math.Log10(1.0 + con.Weight));

            width = width * state._connectionWeightToWidth * state._zoomFactor;

            width = Math.Max(1f, Math.Abs(width));
            Pen pen = new Pen(con.Weight < 0f ? _connectionNegative : _connectionPositive, width);

            // Draw the connection line.
            if (tgtPos.Y > srcPos.Y)
            {
                // Target is below the source. Draw a straight line.
                state._g.DrawLine(pen, srcPos, tgtPos);
            }
            else
            {
                // Target is above source. Draw a back-connection.
                PaintBackConnection(pen, srcPos, tgtPos,
                                    state.GetNodeStateInfo(con.SourceNode),
                                    state.GetNodeStateInfo(con.TargetNode),
                                    state);
            }
        }
        /// <summary>
        /// Create an IOGraph that represents the structure described by the provided INetworkDefinition.
        /// </summary>
        public IOGraph CreateGraph(INetworkDefinition networkDef)
        {
            // Perform depth analysis of network.
            NetworkDepthInfo depthInfo;

            if (networkDef.IsAcyclic)
            {
                AcyclicNetworkDepthAnalysis depthAnalysis = new AcyclicNetworkDepthAnalysis();
                depthInfo = depthAnalysis.CalculateNodeDepths(networkDef);
            }
            else
            {
                CyclicNetworkDepthAnalysis depthAnalysis = new CyclicNetworkDepthAnalysis();
                depthInfo = depthAnalysis.CalculateNodeDepths(networkDef);
            }

            // Create an IOGraph, allocating storage for the node lists.
            INodeList nodeList    = networkDef.NodeList;
            int       nodeCount   = nodeList.Count;
            int       inputCount  = networkDef.InputNodeCount + 1; // + to count bias as an input layer node.
            int       outputCount = networkDef.OutputNodeCount;
            int       hiddenCount = nodeCount - (inputCount + outputCount);
            IOGraph   ioGraph     = new IOGraph(inputCount, outputCount, hiddenCount, 0f, depthInfo._networkDepth);

            // We also build a dictionary of nodes keyed by innovation ID. This is used later
            // to assign connections to nodes.
            Dictionary <uint, GraphNode> nodeDict = new Dictionary <uint, GraphNode>(nodeCount);

            // Loop input nodes.
            int idx = 0;

            for (int i = 0; i < inputCount; i++, idx++)
            {   // Create node, assign it a tag and add it to the node dictionary and the
                // input node list of the IOGraph.
                uint      innovationId = nodeList[idx].Id;
                GraphNode node         = new GraphNode(innovationId.ToString());
                node.AuxData = CreateGraphNodeAuxData(nodeList[idx]);
                node.Depth   = depthInfo._nodeDepthArr[idx];
                nodeDict.Add(innovationId, node);
                ioGraph.InputNodeList.Add(node);
            }

            // Loop output nodes.
            for (int i = 0; i < outputCount; i++, idx++)
            {   // Create node, assign it a tag and add it to the node dictionary and the
                // output node list of the IOGraph.
                uint      innovationId = nodeList[idx].Id;
                GraphNode node         = new GraphNode(innovationId.ToString());
                node.AuxData = CreateGraphNodeAuxData(nodeList[idx]);
                node.Depth   = depthInfo._nodeDepthArr[idx];
                nodeDict.Add(innovationId, node);
                ioGraph.OutputNodeList.Add(node);
            }

            // Loop hidden nodes.
            for (; idx < nodeCount; idx++)
            {   // Create node, assign it a tag and add it to the node dictionary and the
                // hidden node list of the IOGraph.
                uint      innovationId = nodeList[idx].Id;
                GraphNode node         = new GraphNode(innovationId.ToString());
                node.AuxData = CreateGraphNodeAuxData(nodeList[idx]);
                node.Depth   = depthInfo._nodeDepthArr[idx];
                nodeDict.Add(innovationId, node);
                ioGraph.HiddenNodeList.Add(node);
            }

            // Loop connections. Build GraphConnection objects and connect them to their source
            // and target nodes.
            double          maxAbsWeight   = 0.1; // Start at a non-zero value to prevent possibility of a divide by zero occuring.
            IConnectionList connectionList = networkDef.ConnectionList;
            int             connCount      = connectionList.Count;

            for (int i = 0; i < connCount; i++)
            {
                // Create connection object and assign its source and target nodes.
                INetworkConnection connection = connectionList[i];
                GraphNode          sourceNode = nodeDict[connection.SourceNodeId];
                GraphNode          targetNode = nodeDict[connection.TargetNodeId];
                GraphConnection    conn       = new GraphConnection(sourceNode, targetNode, (float)connection.Weight);

                // Add the connection to the connection lists on the source and target nodes.
                sourceNode.OutConnectionList.Add(conn);
                targetNode.InConnectionList.Add(conn);

                // Track weight range oevr all connections.
                double absWeight = Math.Abs(connection.Weight);
                if (absWeight > maxAbsWeight)
                {
                    maxAbsWeight = absWeight;
                }
            }

            ioGraph.ConnectionWeightRange = (float)maxAbsWeight;
            return(ioGraph);
        }
        private void PaintConnection(GraphConnection con, PaintState state)
        {
            Point srcPos = ModelToViewport(con.SourceNode.Position, state);
            Point tgtPos = ModelToViewport(con.TargetNode.Position, state);

            // Connections leave from the base of the source node and enter the top of the target node.
            // Adjust end points to make them neatly terminate just underneath the edge of the endpoint nodes.
            srcPos.Y += (int)(state._nodeDiameterHalf * 0.9f);
            tgtPos.Y -= (int)(state._nodeDiameterHalf * 0.9f);

            // Is any part of the connection within the viewport area?
            if(!IsPointWithinViewport(srcPos, state) && !IsPointWithinViewport(tgtPos, state))
            {   // Skip connection. It's outside the viewport area.
                return;
            }

            // Create a pen for painting the connection.
            // Width is related to connection strength/magnitude.
            float width = (float)(con.Weight < 0.0 ? -Math.Log10(1.0 - con.Weight) : Math.Log10(1.0 + con.Weight));
            width = width * state._connectionWeightToWidth * state._zoomFactor;

            width = Math.Max(1f, Math.Abs(width));
            Pen pen = new Pen(con.Weight < 0f ? _connectionNegative : _connectionPositive, width);
      
            // Draw the connection line.
            if(tgtPos.Y > srcPos.Y)
            {   
                // Target is below the source. Draw a straight line.
                state._g.DrawLine(pen, srcPos, tgtPos);                
            }
            else
            {   
                // Target is above source. Draw a back-connection.
                PaintBackConnection(pen, srcPos, tgtPos,
                                    state.GetNodeStateInfo(con.SourceNode),
                                    state.GetNodeStateInfo(con.TargetNode),
                                    state);
            }
        }
        /// <summary>
        /// Create an IOGraph that represents the structure described by the provided INetworkDefinition.
        /// </summary>
        public IOGraph CreateGraph(INetworkDefinition networkDef)
        {
            // Perform depth analysis of network.
            NetworkDepthInfo depthInfo;
            if(networkDef.IsAcyclic)
            {
                AcyclicNetworkDepthAnalysis depthAnalysis = new AcyclicNetworkDepthAnalysis();
                depthInfo = depthAnalysis.CalculateNodeDepths(networkDef);
            }
            else
            {   
                CyclicNetworkDepthAnalysis depthAnalysis = new CyclicNetworkDepthAnalysis();
                depthInfo = depthAnalysis.CalculateNodeDepths(networkDef);
            }

            // Create an IOGraph, allocating storage for the node lists.
            INodeList nodeList = networkDef.NodeList;
            int nodeCount = nodeList.Count;
            int inputCount = networkDef.InputNodeCount + 1; // + to count bias as an input layer node.
            int outputCount = networkDef.OutputNodeCount;
            int hiddenCount = nodeCount - (inputCount + outputCount);
            IOGraph ioGraph = new IOGraph(inputCount, outputCount, hiddenCount, 0f, depthInfo._networkDepth);
            
            // We also build a dictionary of nodes keyed by innovation ID. This is used later
            // to assign connections to nodes.
            Dictionary<uint, GraphNode> nodeDict = new Dictionary<uint,GraphNode>(nodeCount);

            // Loop input nodes.
            int idx = 0;
            for(int i=0; i<inputCount; i++, idx++)
            {   // Create node, assign it a tag and add it to the node dictionary and the
                // input node list of the IOGraph.
                uint innovationId = nodeList[idx].Id;
                GraphNode node = new GraphNode(innovationId.ToString());
                node.AuxData = CreateGraphNodeAuxData(nodeList[idx]);
                node.Depth = depthInfo._nodeDepthArr[idx];
                nodeDict.Add(innovationId, node);
                ioGraph.InputNodeList.Add(node);
            }

            // Loop output nodes.
            for(int i=0; i<outputCount; i++, idx++)
            {   // Create node, assign it a tag and add it to the node dictionary and the
                // output node list of the IOGraph.
                uint innovationId = nodeList[idx].Id;
                GraphNode node = new GraphNode(innovationId.ToString());
                node.AuxData = CreateGraphNodeAuxData(nodeList[idx]);
                node.Depth = depthInfo._nodeDepthArr[idx];
                nodeDict.Add(innovationId, node);
                ioGraph.OutputNodeList.Add(node);
            }

            // Loop hidden nodes.
            for(; idx<nodeCount; idx++)
            {   // Create node, assign it a tag and add it to the node dictionary and the
                // hidden node list of the IOGraph.
                uint innovationId = nodeList[idx].Id;
                GraphNode node = new GraphNode(innovationId.ToString());
                node.AuxData = CreateGraphNodeAuxData(nodeList[idx]);
                node.Depth = depthInfo._nodeDepthArr[idx];
                nodeDict.Add(innovationId, node);
                ioGraph.HiddenNodeList.Add(node);
            }

            // Loop connections. Build GraphConnection objects and connect them to their source
            // and target nodes.
            double maxAbsWeight = 0.1; // Start at a non-zero value to prevent possibility of a divide by zero occurring.
            IConnectionList connectionList = networkDef.ConnectionList;
            int connCount = connectionList.Count;            
            for(int i=0; i<connCount; i++)
            {
                // Create connection object and assign its source and target nodes.
                INetworkConnection connection = connectionList[i];
                GraphNode sourceNode = nodeDict[connection.SourceNodeId];
                GraphNode targetNode = nodeDict[connection.TargetNodeId];
                GraphConnection conn = new GraphConnection(sourceNode, targetNode, (float)connection.Weight); 
    
                // Add the connection to the connection lists on the source and target nodes.
                sourceNode.OutConnectionList.Add(conn);
                targetNode.InConnectionList.Add(conn);

                // Track weight range over all connections.
                double absWeight = Math.Abs(connection.Weight);
                if(absWeight > maxAbsWeight) {
                    maxAbsWeight = absWeight;
                }
            }

            ioGraph.ConnectionWeightRange = (float)maxAbsWeight;
            return ioGraph;
        }