public override void Compute(CancellationToken cancellationToken) { if (VisitedGraph.VertexCount == 1) { VertexPositions.Add(VisitedGraph.Vertices.First(), new Point(0, 0)); return; } #region Initialization _distances = new double[VisitedGraph.VertexCount, VisitedGraph.VertexCount]; _edgeLengths = new double[VisitedGraph.VertexCount, VisitedGraph.VertexCount]; _springConstants = new double[VisitedGraph.VertexCount, VisitedGraph.VertexCount]; _vertices = new TVertex[VisitedGraph.VertexCount]; _positions = new Point[VisitedGraph.VertexCount]; //initializing with random positions InitializeWithRandomPositions(Parameters.Width, Parameters.Height); //copy positions into array (speed-up) int index = 0; foreach (var v in VisitedGraph.Vertices) { _vertices[index] = v; _positions[index] = VertexPositions[v]; index++; } //calculating the diameter of the graph //TODO check the diameter algorithm _diameter = VisitedGraph.GetDiameter <TVertex, TEdge, TGraph>(out _distances); //L0 is the length of a side of the display area double l0 = Math.Min(Parameters.Width, Parameters.Height); //ideal length = L0 / max d_i,j _idealEdgeLength = (l0 / _diameter) * Parameters.LengthFactor; //calculating the ideal distance between the nodes for (int i = 0; i < VisitedGraph.VertexCount - 1; i++) { cancellationToken.ThrowIfCancellationRequested(); for (int j = i + 1; j < VisitedGraph.VertexCount; j++) { cancellationToken.ThrowIfCancellationRequested(); //distance between non-adjacent vertices double dist = _diameter * Parameters.DisconnectedMultiplier; //calculating the minimal distance between the vertices if (_distances[i, j] != double.MaxValue) { dist = Math.Min(_distances[i, j], dist); } if (_distances[j, i] != double.MaxValue) { dist = Math.Min(_distances[j, i], dist); } _distances[i, j] = _distances[j, i] = dist; _edgeLengths[i, j] = _edgeLengths[j, i] = _idealEdgeLength * dist; _springConstants[i, j] = _springConstants[j, i] = Parameters.K / Math.Pow(dist, 2); } } #endregion int n = VisitedGraph.VertexCount; if (n == 0) { return; } //TODO check this condition for (int currentIteration = 0; currentIteration < Parameters.MaxIterations; currentIteration++) { cancellationToken.ThrowIfCancellationRequested(); #region An iteration double maxDeltaM = double.NegativeInfinity; int pm = -1; //get the 'p' with the max delta_m for (int i = 0; i < n; i++) { cancellationToken.ThrowIfCancellationRequested(); double deltaM = CalculateEnergyGradient(i); if (maxDeltaM < deltaM) { maxDeltaM = deltaM; pm = i; } } //TODO is needed? if (pm == -1) { return; } //calculating the delta_x & delta_y with the Newton-Raphson method //there is an upper-bound for the while (deltaM > epsilon) {...} cycle (100) for (int i = 0; i < 100; i++) { _positions[pm] += CalcDeltaXY(pm); double deltaM = CalculateEnergyGradient(pm); //real stop condition if (deltaM < double.Epsilon) { break; } } //what if some of the vertices would be exchanged? if (Parameters.ExchangeVertices && maxDeltaM < double.Epsilon) { double energy = CalcEnergy(); for (int i = 0; i < n - 1; i++) { cancellationToken.ThrowIfCancellationRequested(); for (int j = i + 1; j < n; j++) { cancellationToken.ThrowIfCancellationRequested(); double xenergy = CalcEnergyIfExchanged(i, j); if (energy > xenergy) { Point p = _positions[i]; _positions[i] = _positions[j]; _positions[j] = p; return; } } } } #endregion /* if ( ReportOnIterationEndNeeded ) * Report( currentIteration );*/ } Report(Parameters.MaxIterations); }