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; }