public static void Run(Graph graph, Action refresh, Size size) { if (!IsRun) { IsRun = true; ThreadPool.QueueUserWorkItem(state => { var avgEdgeLength = graph.SelectMany(x => x.Edges.Select(e => e.GetLength())).Average(); Func <double> GetSolutionCost = () => CalcSolutionCost(graph, avgEdgeLength); var rand = new Random(DateTime.Now.Millisecond); Temperature = INITIAL_TEMPERATURE; double solutionCost = GetSolutionCost(); for (int i = 0; i < COOLING_STEP; i++) { Temperature *= COOLING_FRACTION; var startValue = solutionCost; for (int j = 0; j < STEPS_PER_TEMP; j++) { var vertexIndex = rand.Next(0, graph.Count); var vertex = graph[vertexIndex]; var moveDirection = (Direction)rand.Next(0, 7); var moveDistance = (float)rand.NextDouble() * avgEdgeLength; var position = vertex.Position; Move(vertex, moveDirection, moveDistance, size); refresh(); var flip = rand.NextDouble() * 1.1; var currentSolutionCost = GetSolutionCost(); var delta = solutionCost - currentSolutionCost; var exponent = (-delta / solutionCost) / (K * Temperature); var merit = Math.Pow(Math.E, exponent); if (delta < 0) //Принять удачный вариант { solutionCost = currentSolutionCost; refresh(); } else { if (merit > flip) //Принять неудачный вариант { solutionCost = currentSolutionCost; refresh(); } else //Отклонить { vertex.Position = position; } } } if (solutionCost - startValue < 0) { Temperature = Temperature / COOLING_FRACTION; } } IsRun = false; }); } }
private static double CalcSolutionCost(Graph graph, float edgeLength) { var c = graph.SelectMany(x => x.Edges.Select(e => e.GetLength())).Where(x => Math.Abs(x / edgeLength) > 0.9 && Math.Abs(x / edgeLength) < 1.1).Count() / 2; return((((double)c * 2) / graph.SelectMany(x => x.Edges).Count()) * 100.0); }