Пример #1
0
        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);
        }