public IEnumerable <TLayout> Evolve(TLayout initialLayout, Chain <TNode> chain, int count) { for (int i = 0; i < count; i++) { var copy = initialLayout.SmartClone(); layoutOperations.AddChain(copy, chain.Nodes, true, out var iterationsCount); foreach (var _ in chain.Nodes) { OnPerturbed?.Invoke(this, copy); } if (layoutOperations.IsLayoutValid(copy)) { // TODO: why chain.Nodes instead of chain? if (layoutOperations.TryCompleteChain(copy, chain.Nodes)) { yield return(copy); } } } }
/// <inheritdoc /> public IEnumerable <TLayout> Evolve(TLayout initialLayout, Chain <TNode> chain, int count) { var configuration = GetConfiguration(chain.Number); if (!chain.IsFromFace && configuration.HandleTreesGreedily) { var iters = 0; var lastEventIters = 0; for (int i = 0; i < 2; i++) { if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } for (int k = 0; k < 1; k++) { if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } var copy = initialLayout.SmartClone(); LayoutOperations.AddChain(copy, chain.Nodes, true, out var addChainIterationsCount); iters += addChainIterationsCount; // An event must be sent in order for the early stopping handler to work OnPerturbed?.Invoke(this, copy); if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } if (LayoutOperations.IsLayoutValid(copy)) { if (LayoutOperations.TryCompleteChain(copy, chain.Nodes)) { OnPerturbed?.Invoke(this, copy); if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.LayoutGenerated, IterationsSinceLastEvent = iters - lastEventIters, IterationsTotal = iters, LayoutsGenerated = -1, ChainNumber = chain.Number, }); lastEventIters = iters; yield return(copy); break; } } OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.OutOfIterations, IterationsSinceLastEvent = iters - lastEventIters, IterationsTotal = iters, LayoutsGenerated = -1, ChainNumber = chain.Number, }); lastEventIters = iters; } } yield break; } if (addNodesGreedilyBeforeEvolve) { LayoutOperations.AddChain(initialLayout, chain.Nodes, true, out var addChainIterationsCount); } const double p0 = 0.2d; const double p1 = 0.01d; var t0 = -1d / Math.Log(p0); var t1 = -1d / Math.Log(p1); var ratio = Math.Pow(t1 / t0, 1d / (configuration.Cycles - 1)); var deltaEAvg = 0d; var acceptedSolutions = 1; var t = t0; var layouts = new List <TLayout>(); var originalLayout = initialLayout; var currentLayout = originalLayout; #region Debug output //if (withDebugOutput) //{ // Console.WriteLine($"Initial energy: {layoutOperations.GetEnergy(currentLayout)}"); //} #endregion var numberOfFailures = 0; var stageTwoFailures = 0; var iterations = 0; var lastEventIterations = 0; var shouldStop = false; for (var i = 0; i < configuration.Cycles; i++) { var wasAccepted = false; #region Random restarts if (enableRandomRestarts) { if (ShouldRestart(numberOfFailures)) { OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.RandomRestart, IterationsSinceLastEvent = iterations - lastEventIterations, IterationsTotal = iterations, LayoutsGenerated = layouts.Count, ChainNumber = chain.Number, }); yield break; } } #endregion if (iterations - lastEventIterations > configuration.MaxIterationsWithoutSuccess) { break; } if (shouldStop) { break; } for (var j = 0; j < configuration.TrialsPerCycle; j++) { if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } if (stageTwoFailures > configuration.MaxStageTwoFailures) { shouldStop = true; break; } iterations++; var perturbedLayout = PerturbLayout(currentLayout, chain.Nodes, out var energyDelta); OnPerturbed?.Invoke(this, perturbedLayout); // TODO: can we check the energy instead? if (LayoutOperations.IsLayoutValid(perturbedLayout, chain.Nodes)) { #region Random restarts if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnValid) { wasAccepted = true; if (randomRestartsResetCounter) { numberOfFailures = 0; } } #endregion // TODO: wouldn't it be too slow to compare againts all? if (IsDifferentEnough(perturbedLayout, layouts)) { // TODO 2SG: should we clone before TryCompleteChain or should TryCompleteChain not change the layout? var newLayout = perturbedLayout.SmartClone(); var shouldContinue = LayoutOperations.TryCompleteChain(newLayout, chain.Nodes); if (shouldContinue) { layouts.Add(newLayout); OnValid?.Invoke(this, newLayout); #region Random restarts if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnValidAndDifferent) { wasAccepted = true; if (randomRestartsResetCounter) { numberOfFailures = 0; } } #endregion OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.LayoutGenerated, IterationsSinceLastEvent = iterations - lastEventIterations, IterationsTotal = iterations, LayoutsGenerated = layouts.Count, ChainNumber = chain.Number, }); yield return(newLayout); lastEventIterations = iterations; stageTwoFailures = 0; #region Debug output //if (withDebugOutput) //{ // Console.WriteLine($"Found layout, cycle {i}, trial {j}, energy {layoutOperations.GetEnergy(perturbedLayout)}"); //} #endregion if (layouts.Count >= count) { #region Debug output //if (withDebugOutput) //{ // Console.WriteLine($"Returning {layouts.Count} partial layouts"); //} #endregion yield break; } } else { stageTwoFailures++; OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.StageTwoFailure, IterationsSinceLastEvent = iterations - lastEventIterations, IterationsTotal = iterations, LayoutsGenerated = layouts.Count, ChainNumber = chain.Number, ResetsIterationsSinceLastEvent = false, }); } } } var deltaAbs = Math.Abs(energyDelta); var accept = false; if (energyDelta > 0) { if (i == 0 && j == 0) { deltaEAvg = deltaAbs * 15; } var p = Math.Pow(Math.E, -deltaAbs / (deltaEAvg * t)); if (Random.NextDouble() < p) { accept = true; } } else { accept = true; } if (accept) { acceptedSolutions++; currentLayout = perturbedLayout; deltaEAvg = (deltaEAvg * (acceptedSolutions - 1) + deltaAbs) / acceptedSolutions; #region Random restarts if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnAccepted) { wasAccepted = true; if (randomRestartsResetCounter) { numberOfFailures = 0; } } #endregion } } if (!wasAccepted) { numberOfFailures++; } t = t * ratio; } OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.OutOfIterations, IterationsSinceLastEvent = iterations - lastEventIterations, IterationsTotal = iterations, LayoutsGenerated = layouts.Count, ChainNumber = chain.Number, }); }