public void PaintNetwork(Graphics g, NetworkModel nm, float zoomFactor, Point viewportOrigin, Size viewportSize, double connectionWeightMin, double connectionWeightRange) { // Store painting parameters. this.zoomFactor = zoomFactor; this.viewportOrigin = viewportOrigin; this.viewportSize = viewportSize; this.connectionWeightMin = connectionWeightMin; this.connectionWeightRange = connectionWeightRange; // Some pre-calculated values. this.viewportBound = new Point(viewportOrigin.X + viewportSize.Width, viewportOrigin.Y + viewportSize.Height); neuronDiameter = (int)(NEURON_DIAMETER_BASE * zoomFactor); neuronDiameterHalfed = (int)((NEURON_DIAMETER_BASE * zoomFactor) / 2.0F); backConnectionLegLength = (NEURON_DIAMETER_BASE * zoomFactor * 1.6F); connectionWidthFactor = (float)(connectionWeightRange / 2.0); fontNeuronId = new Font("Microsoft Sans Serif", (float)Math.Min(Math.Max(0.2, 7.0F * zoomFactor), Single.MaxValue)); // Assign a ConnectionPoints object to each neuron. int neuronCount = nm.MasterNeuronList.Count; for (int neuronIdx = 0; neuronIdx < neuronCount; neuronIdx++) { nm.MasterNeuronList[neuronIdx].AuxPaintingData = new ConnectionPoints(); } //----- Painting code. // Paint all connections first. The neurons are painted over the top to // cover up any loose ends. for (int neuronIdx = 0; neuronIdx < neuronCount; neuronIdx++) { ModelNeuron neuron = nm.MasterNeuronList[neuronIdx]; // Incoming connections. int connectionCount = neuron.InConnectionList.Count; for (int connectionIdx = 0; connectionIdx < connectionCount; connectionIdx++) { PaintConnection(g, neuron.InConnectionList[connectionIdx]); } } foreach (ModelNeuron neuron in nm.MasterNeuronList) { PaintNeuron(g, neuron); } }
private void UpdateModelBounds(ModelNeuron neuron) { if (neuron.Position.X > bounds.Width) { bounds.Width = neuron.Position.X; } if (neuron.Position.Y > bounds.Height) { bounds.Height = neuron.Position.Y; } }
private void PaintNeuron(Graphics g, ModelNeuron neuron) { Point neuronPos = DocToViewport(neuron.Position); // Is the neuron within the viewport area? if (!IsPointWithinViewport(neuronPos)) { // Don't waste time painting this neuron. return; } Point p = new Point(neuronPos.X - neuronDiameterHalfed, neuronPos.Y - neuronDiameterHalfed); Size s = new Size(neuronDiameter, neuronDiameter); Rectangle r = new Rectangle(p, s); Brush b; //g.FillEllipse(brushNeuron, r); if (neuron.ActivationFunction == NeuralNetwork.ActivationFunctionFactory.GetActivationFunction("Gaussian")) { b = brushNeuronGaussian; } else if (neuron.ActivationFunction == NeuralNetwork.ActivationFunctionFactory.GetActivationFunction("Linear")) { b = brushNeuronLinear; } else if (neuron.ActivationFunction == NeuralNetwork.ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid")) { b = brushNeuronSigmoid; } else if (neuron.ActivationFunction == NeuralNetwork.ActivationFunctionFactory.GetActivationFunction("Sine")) { b = brushNeuronSine; } else { b = brushNeuronCore; } g.FillRectangle(b, r); g.DrawRectangle(penBlack, r); // Draw the neuron ID. neuronPos.X += neuronDiameterHalfed + 1; neuronPos.Y -= neuronDiameterHalfed / 2; g.DrawString(neuron.Id.ToString(), fontNeuronId, brushBlack, neuronPos); }
public void Layout(NetworkModel nm, Size areaSize) { // Use this to keep track of the coordinate bounds of the network (maxX, maxY). bounds = new Size(0, 0); //----- Determine how many layers we are going arrange the neurons into. int inputCount = nm.InputNeuronList.Count; int outputCount = nm.OutputNeuronList.Count; int hiddenCount = nm.MasterNeuronList.Count - (inputCount + outputCount); float heightWidthRatio = (float)areaSize.Height / (float)areaSize.Width; // Default to 2 (input and output layers). int numLayers = 2; int numHiddenLayers = 0; if (hiddenCount > 0) { // Arrange as if there no input/output layers. double sqrtHidden = Math.Sqrt(hiddenCount); numHiddenLayers = (int)Math.Floor(sqrtHidden * heightWidthRatio); // Now factor in the input/output layers. numHiddenLayers = Math.Max(1, numHiddenLayers - 2); numLayers = 2 + numHiddenLayers; } //----- Arrange the neurons. int heightLayers = areaSize.Height - 2 * MARGIN_Y; int yIncrement = areaSize.Height / (numLayers + 1); int yCurrent = MARGIN_Y + yIncrement; double yIncrementHalfed = yIncrement / 2.0; // Input layer. Place all input neurons in one layer. int widthLayer = areaSize.Width - 2 * MARGIN_X; int xIncrement = widthLayer / (inputCount + 1); int xCurrent = MARGIN_X + xIncrement; foreach (ModelNeuron modelNeuron in nm.InputNeuronList) { modelNeuron.Position = new Point(xCurrent, yCurrent); modelNeuron.HasPositionInfo = true; UpdateModelBounds(modelNeuron); xCurrent += xIncrement; } // Increment yCurrent, ready for the next layer. yCurrent += yIncrement; // Hidden layers. if (numLayers > 0) { // Keep track of which neuron is being positioned. int neuronIdx = 0; // calculate the max number of neurons in any hidden layer. int layerNeuronsMax = (int)Math.Ceiling((float)hiddenCount / (float)numHiddenLayers); // Keep track of how many neurons remain to be positioned. int neuronsRemaining = hiddenCount; for (int hiddenLayer = 0; hiddenLayer < numHiddenLayers; hiddenLayer++) { // Calculate the number of neurons in this layer. int layerNeuronCount = Math.Min(neuronsRemaining, layerNeuronsMax); // Position neurons in this layer. xIncrement = widthLayer / (layerNeuronCount + 1); xCurrent = MARGIN_X + xIncrement; for (int i = 0; i < layerNeuronCount; i++) { ModelNeuron modelNeuron = nm.HiddenNeuronList[neuronIdx++]; modelNeuron.Position = new Point( xCurrent, yCurrent); //yCurrent + (int)(((random.NextDouble()*(double)yIncrement)-yIncrementHalfed)*JIGGLE_PROPORTION)); modelNeuron.HasPositionInfo = true; UpdateModelBounds(modelNeuron); xCurrent += xIncrement; } // Increment yCurrent, ready for the next layer. yCurrent += yIncrement; neuronsRemaining -= layerNeuronCount; } } // Output layer. xIncrement = widthLayer / (outputCount + 1); xCurrent = MARGIN_X + xIncrement; foreach (ModelNeuron modelNeuron in nm.OutputNeuronList) { modelNeuron.Position = new Point( xCurrent, yCurrent); //yCurrent + (int)(((random.NextDouble()*(double)yIncrement)-yIncrementHalfed)*JIGGLE_PROPORTION)); modelNeuron.HasPositionInfo = true; UpdateModelBounds(modelNeuron); xCurrent += xIncrement; } nm.Bounds = bounds; }