private bool TryLayoutNode(TLayout layout, TNode node, out TLayout newLayout)
        {
            // possibleShapes.Shuffle(Random);
            var neighbouringConfigurations = GetNeighbouringConfigurations(layout, node);

            var possibleShapes = LayoutOperations.GetShapesForNode(node);
            var notUsedShapes  = possibleShapes.Where(x => neighbouringConfigurations.All(y => !y.ShapeContainer.Equals(x))).ToList();

            if (notUsedShapes.Count != 0)
            {
                possibleShapes = notUsedShapes;
            }

            for (int i = 0; i < NumberOfAttemptsPerNode; i++)
            {
                var shape    = possibleShapes.GetRandom(Random);
                var position = LayoutOperations.GetRandomPosition(shape, neighbouringConfigurations);
                var isValid  = LayoutOperations.IsValid(layout, node, shape, position);

                // TODO: this is not really needed
                newLayout = layout.SmartClone();
                newLayout.SetConfiguration(node, CreateConfiguration(shape, position));
                OnPerturbed?.Invoke(newLayout);

                if (isValid)
                {
                    return(true);
                }
            }

            newLayout = default;
            return(false);
        }
Example #2
0
        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);
                    }
                }
            }
        }
        private void SetupGenerator()
        {
            var mapping       = mapDescription.GetMapping();
            var chainsGeneric = configuration.Chains;

            if (chainsGeneric == null)
            {
                var chainDecomposition = new TwoStageChainDecomposition <TNode>(mapDescriptionOriginal, new BreadthFirstChainDecomposition <TNode>(configuration.ChainDecompositionConfiguration ?? new ChainDecompositionConfiguration()));
                chainsGeneric = chainDecomposition.GetChains(mapDescriptionOriginal.GetGraph());
            }

            var chains = chainsGeneric
                         .Select(x => new Chain <int>(x.Nodes.Select(y => mapping[y]).ToList(), x.Number))
                         .ToList();

            var generatorPlanner = new GeneratorPlanner <Layout <Configuration <CorridorsData> >, int>(configuration.SimulatedAnnealingMaxBranching);

            var configurationSpacesGenerator = new ConfigurationSpacesGenerator(
                new PolygonOverlap(),
                DoorHandler.DefaultHandler,
                new OrthogonalLineIntersection(),
                new GridPolygonUtils());
            var configurationSpaces = configurationSpacesGenerator.GetConfigurationSpaces <Configuration <CorridorsData> >(mapDescription);

            //var corridorConfigurationSpaces = mapDescription.IsWithCorridors ? configurationSpacesGenerator.Generate<TNode, Configuration<CorridorsData>>(mapDescription, mapDescription.CorridorsOffsets) : configurationSpaces;
            var corridorConfigurationSpaces = configurationSpaces;

            var averageSize    = configurationSpaces.GetAverageSize();
            var polygonOverlap = new FastPolygonOverlap();

            var stageOneConstraints =
                new List <INodeConstraint <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>,
                                           CorridorsData> >
            {
                new BasicConstraint <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>,
                                     CorridorsData, IntAlias <PolygonGrid2D> >(
                    new FastPolygonOverlap(),
                    averageSize,
                    configurationSpaces
                    ),
                new CorridorConstraints <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, CorridorsData, IntAlias <PolygonGrid2D> >(
                    mapDescription,
                    averageSize,
                    corridorConfigurationSpaces
                    ),
            };

            if (!configuration.RoomsCanTouch)
            {
                stageOneConstraints.Add(new TouchingConstraints <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, CorridorsData, IntAlias <PolygonGrid2D> >(
                                            mapDescription,
                                            polygonOverlap
                                            ));
            }

            var stageOneConstraintsEvaluator = new ConstraintsEvaluator <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, IntAlias <PolygonGrid2D>, CorridorsData>(stageOneConstraints);

            //if (mapDescription.IsWithCorridors)
            //{
            //    layoutOperations.AddNodeConstraint(new CorridorConstraints<Layout<Configuration<CorridorsData>>, int, Configuration<CorridorsData>, CorridorsData, IntAlias<GridPolygon>>(
            //        mapDescription,
            //        averageSize,
            //        corridorConfigurationSpaces
            //    ));

            //    if (!false) // TODO:
            //    {
            //        var polygonOverlap = new FastPolygonOverlap();
            //        layoutOperations.AddNodeConstraint(new TouchingConstraints<Layout<Configuration<CorridorsData>>, int, Configuration<CorridorsData>, CorridorsData, IntAlias<GridPolygon>>(
            //            mapDescription,
            //            polygonOverlap
            //        ));
            //    }
            //}


            var roomShapesHandler = new RoomShapesHandler <int, Configuration <CorridorsData> >(
                configurationSpaces,
                configurationSpaces.GetIntAliasMapping(),
                mapDescription,
                configuration.RepeatModeOverride
                );

            var layoutOperations = new LayoutOperations <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, IntAlias <PolygonGrid2D>, CorridorsData>(corridorConfigurationSpaces, configurationSpaces.GetAverageSize(), mapDescription, stageOneConstraintsEvaluator, stageOneConstraintsEvaluator, roomShapesHandler, configuration.ThrowIfRepeatModeNotSatisfied);

            var initialLayout   = new Layout <Configuration <CorridorsData> >(mapDescription.GetGraph());
            var layoutConverter =
                new BasicLayoutConverter <Layout <Configuration <CorridorsData> >, TNode,
                                          Configuration <CorridorsData> >(mapDescription, configurationSpaces,
                                                                          configurationSpaces.GetIntAliasMapping());

            var layoutEvolver =
                new PlatformersEvolver <Layout <Configuration <CorridorsData> >, int,
                                        Configuration <CorridorsData> >(layoutOperations);

            generator = new ChainBasedGenerator <Layout <Configuration <CorridorsData> >, MapLayout <TNode>, int>(initialLayout, generatorPlanner, chains, layoutEvolver, layoutConverter);

            generator.OnRandomInjected += (random) =>
            {
                ((IRandomInjectable)configurationSpaces).InjectRandomGenerator(random);
                ((IRandomInjectable)layoutOperations).InjectRandomGenerator(random);
                ((IRandomInjectable)layoutEvolver).InjectRandomGenerator(random);
                ((IRandomInjectable)layoutConverter).InjectRandomGenerator(random);
            };

            generator.OnCancellationTokenInjected += (token) =>
            {
                ((ICancellable)generatorPlanner).SetCancellationToken(token);
                ((ICancellable)layoutEvolver).SetCancellationToken(token);
            };

            // layoutEvolver.OnEvent += (sender, args) => OnSimulatedAnnealingEvent?.Invoke(sender, args);
            layoutEvolver.OnPerturbed          += (sender, layout) => OnPerturbed?.Invoke(layoutConverter.Convert(layout, false));
            layoutEvolver.OnPerturbed          += (sender, layout) => OnPerturbedInternal?.Invoke(layout);
            layoutEvolver.OnValid              += (sender, layout) => OnPartialValid?.Invoke(layoutConverter.Convert(layout, true));
            generatorPlanner.OnLayoutGenerated += layout => OnValid?.Invoke(layoutConverter.Convert(layout, true));
        }
        /// <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,
            });
        }
        private List <Layout> GetExtendedLayouts(Layout layout, List <int> chain, bool lastChain)
        {
            var cycles         = 50;
            var trialsPerCycle = 500;

            var p0                = 0.2d;
            var p1                = 0.01d;
            var t0                = -1d / Math.Log(p0);
            var t1                = -1d / Math.Log(p1);
            var ratio             = Math.Pow(t1 / t0, 1d / (cycles - 1));
            var deltaEAvg         = 0d;
            var acceptedSolutions = 1;

            var t = t0;

            var layouts        = new List <Layout>();
            var originalLayout = layout;             //AddChainToLayout(layout, chain);
            var currentLayout  = originalLayout;

            if (WithDebug)
            {
                Console.WriteLine($"Initial energy: {currentLayout.GetEnergy()}");
            }

            var numFailures = 0;

            for (var i = 0; i < cycles; i++)
            {
                var wasAccepted = false;

                if (numFailures > 8 && Random.Next(0, 2) == 0)
                {
                    if (WithDebug)
                    {
                        Console.WriteLine($"Break, we got {numFailures} failures");
                    }
                    break;
                }

                if (numFailures > 6 && Random.Next(0, 3) == 0)
                {
                    if (WithDebug)
                    {
                        Console.WriteLine($"Break, we got {numFailures} failures");
                    }
                    break;
                }

                if (numFailures > 4 && Random.Next(0, 5) == 0)
                {
                    if (WithDebug)
                    {
                        Console.WriteLine($"Break, we got {numFailures} failures");
                    }
                    break;
                }

                if (numFailures > 2 && Random.Next(0, 7) == 0)
                {
                    if (WithDebug)
                    {
                        Console.WriteLine($"Break, we got {numFailures} failures");
                    }
                    break;
                }

                for (var j = 0; j < trialsPerCycle; j++)
                {
                    iterationsCount++;
                    var perturbedLayout = PerturbLayout(currentLayout, chain, out var energyDelta);                     // TODO: locally perturb the layout

                    OnPerturbed?.Invoke((ILayout <TNode, TPolygon, TPosition, IntLine>)perturbedLayout);

                    // TODO: should probably check only the perturbed node - other nodes did not change
                    if (IsLayoutValid(perturbedLayout))
                    {
                        OnValid?.Invoke((ILayout <TNode, TPolygon, TPosition, IntLine>)perturbedLayout);

                        // TODO: wouldn't it be too slow to compare againts all?
                        if (layouts.TrueForAll(x => x.GetDifference(perturbedLayout, chain) > 2 * MinimumDifference))
                        {
                            wasAccepted = true;
                            AddDoors(new List <Layout>()
                            {
                                perturbedLayout
                            });
                            layouts.Add(perturbedLayout);
                            OnValidAndDifferent?.Invoke((ILayout <TNode, TPolygon, TPosition, IntLine>)perturbedLayout);

                            if (WithDebug)
                            {
                                Console.WriteLine($"Found layout, cycle {i}, trial {j}, energy {perturbedLayout.GetEnergy()}");
                            }

                            if (layouts.Count >= 15)
                            {
                                if (WithDebug)
                                {
                                    Console.WriteLine($"Returning {layouts.Count} partial layouts");
                                }

                                return(layouts);
                            }
                        }
                    }

                    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;
                    }
                }

                if (!wasAccepted)
                {
                    numFailures++;
                }

                t = t * ratio;
            }

            if (WithDebug)
            {
                Console.WriteLine($"Returning {layouts.Count} partial layouts");
            }

            return(layouts);
        }
Example #6
0
        /// <inheritdoc />
        public IEnumerable <TLayout> Evolve(TLayout initialLayout, IList <TNode> chain, int count)
        {
            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 / (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;

            for (var i = 0; i < Cycles; i++)
            {
                var wasAccepted = false;

                #region Random restarts

                if (enableRandomRestarts)
                {
                    if (ShouldRestart(numberOfFailures))
                    {
                        break;
                    }
                }

                #endregion

                for (var j = 0; j < TrialsPerCycle; j++)
                {
                    if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested)
                    {
                        yield break;
                    }

                    var perturbedLayout = PerturbLayout(currentLayout, chain, out var energyDelta);

                    OnPerturbed?.Invoke(perturbedLayout);

                    // TODO: can we check the energy instead?
                    if (LayoutOperations.IsLayoutValid(perturbedLayout, chain))
                    {
                        #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))
                        {
                            var shouldContinue = true;

                            // TODO: should it be like this?
                            if (LayoutOperations is ILayoutOperationsWithCorridors <TLayout, TNode> layoutOperationsWithCorridors)
                            {
                                shouldContinue = layoutOperationsWithCorridors.AddCorridors(perturbedLayout, chain);
                            }

                            if (shouldContinue)
                            {
                                layouts.Add(perturbedLayout);
                                OnValid?.Invoke(perturbedLayout);

                                #region Random restarts
                                if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnValidAndDifferent)
                                {
                                    wasAccepted = true;

                                    if (randomRestartsResetCounter)
                                    {
                                        numberOfFailures = 0;
                                    }
                                }
                                #endregion

                                yield return(perturbedLayout);

                                #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;
                                }
                            }
                        }
                    }

                    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;
            }
        }
        private void SetupGenerator()
        {
            var mapping       = levelDescriptionMapped.GetMapping();
            var chainsGeneric = configuration.Chains;

            // Create chain decomposition
            if (chainsGeneric == null)
            {
                var chainDecomposition = new Common.TwoStageChainDecomposition <TRoom>(levelDescription, new BreadthFirstChainDecomposition <TRoom>(configuration.ChainDecompositionConfiguration ?? new ChainDecompositionConfiguration()));
                chainsGeneric = chainDecomposition.GetChains(levelDescription.GetGraph());
            }

            var chains = chainsGeneric
                         .Select(x => new Chain <RoomNode <TRoom> >(x.Nodes.Select(y => mapping[y]).ToList(), x.Number)
            {
                IsFromFace = x.IsFromFace
            })
                         .ToList();

            // Create generator planner
            var generatorPlanner = new GeneratorPlanner <Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >, RoomNode <TRoom> >(configuration.SimulatedAnnealingMaxBranching);

            // Create configuration spaces
            var configurationSpacesGenerator = new ConfigurationSpacesGenerator(
                new PolygonOverlap(),
                DoorHandler.DefaultHandler,
                new OrthogonalLineIntersection(),
                new GridPolygonUtils());

            // var configurationSpaces = configurationSpacesGenerator.GetConfigurationSpaces<ConfigurationNew2<CorridorsDataNew>>(mapDescription);
            var simpleConfigurationSpaces = new ConfigurationSpacesGrid2D <ConfigurationGrid2D <TRoom, EnergyData>, RoomNode <TRoom> >(levelDescriptionMapped);

            // Needlessly complex for backwards compatibility

            #region IntAliasMapping

            var roomDescriptions             = levelDescriptionMapped.GetGraph().Vertices.ToDictionary(x => x, x => (RoomDescriptionGrid2D)levelDescriptionMapped.GetRoomDescription(x));
            var roomTemplates                = roomDescriptions.Values.SelectMany(x => x.RoomTemplates).Distinct().ToList();
            var roomTemplateInstances        = roomTemplates.ToDictionary(x => x, configurationSpacesGenerator.GetRoomTemplateInstances);
            var roomTemplateInstancesMapping = roomTemplateInstances.SelectMany(x => x.Value).CreateIntMapping();
            var intAliasMapping              = new TwoWayDictionary <RoomTemplateInstanceGrid2D, IntAlias <PolygonGrid2D> >();

            foreach (var shape1 in roomTemplateInstancesMapping.Keys)
            {
                foreach (var shape2 in roomTemplateInstancesMapping.Keys)
                {
                    if (!intAliasMapping.ContainsKey(shape1))
                    {
                        var newAlias = new IntAlias <PolygonGrid2D>(intAliasMapping.Count, shape1.RoomShape);
                        intAliasMapping.Add(shape1, newAlias);
                        shape1.RoomShapeAlias = newAlias;
                    }
                    if (!intAliasMapping.ContainsKey(shape2))
                    {
                        var newAlias = new IntAlias <PolygonGrid2D>(intAliasMapping.Count, shape2.RoomShape);
                        intAliasMapping.Add(shape2, newAlias);
                        shape2.RoomShapeAlias = newAlias;
                    }
                }
            }

            // TODO: remove when possible
            foreach (var pair in intAliasMapping)
            {
                pair.Key.RoomShapeAlias = pair.Value;
            }

            var shapesForNodes = new Dictionary <RoomNode <TRoom>, List <WeightedShape> >();
            foreach (var vertex in levelDescriptionMapped.GetGraph().Vertices)
            {
                shapesForNodes.Add(vertex, new List <WeightedShape>());
                // var roomDescription = levelDescriptionMapped.GetRoomDescription(vertex);
                var roomDescription = roomDescriptions[vertex];

                foreach (var roomTemplate in roomDescription.RoomTemplates)
                {
                    var instances = roomTemplateInstances[roomTemplate];

                    foreach (var roomTemplateInstance in instances)
                    {
                        shapesForNodes[vertex].Add(new WeightedShape(intAliasMapping[roomTemplateInstance], 1d / instances.Count));
                    }
                }
            }

            var usedShapes = new HashSet <int>();
            var allShapes  = new List <IntAlias <PolygonGrid2D> >();
            foreach (var vertex in levelDescriptionMapped.GetGraph().Vertices)
            {
                var shapes = shapesForNodes[vertex];

                foreach (var shape in shapes)
                {
                    if (!usedShapes.Contains(shape.Shape.Alias))
                    {
                        allShapes.Add(shape.Shape);
                        usedShapes.Add(shape.Shape.Alias);
                    }
                }
            }

            var averageSize = (int)allShapes.Select(x => x.Value.BoundingRectangle).Average(x => (x.Width + x.Height) / 2);

            #endregion



            // var averageSize = configurationSpaces.GetAverageSize();

            var energyUpdater     = new BasicEnergyUpdater <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData> >(10 * averageSize);
            var roomShapeGeometry = new FastGridPolygonGeometry <ConfigurationGrid2D <TRoom, EnergyData>, RoomNode <TRoom> >();

            // Create generator constraints
            var stageOneConstraints =
                new List <INodeConstraint <ILayout <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData> >, RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>,
                                           EnergyData> >
            {
                new BasicConstraint <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, EnergyData>(
                    roomShapeGeometry,
                    simpleConfigurationSpaces,
                    levelDescriptionMapped,
                    configuration.OptimizeCorridorConstraints
                    ),
                new CorridorConstraint <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, EnergyData>(
                    levelDescriptionMapped,
                    simpleConfigurationSpaces,
                    roomShapeGeometry
                    ),
            };

            if (levelDescription.MinimumRoomDistance > 0)
            {
                stageOneConstraints.Add(new MinimumDistanceConstraint <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, EnergyData>(
                                            levelDescriptionMapped,
                                            roomShapeGeometry,
                                            levelDescription.MinimumRoomDistance
                                            ));
            }

            var constraintsEvaluator = new ConstraintsEvaluator <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, EnergyData>(stageOneConstraints, energyUpdater);

            var roomShapesHandler = new RoomShapesHandlerGrid2D <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData> >(
                intAliasMapping,
                levelDescriptionMapped,
                shapesForNodes,
                levelDescription.RoomTemplateRepeatModeOverride,
                levelDescription.RoomTemplateRepeatModeDefault
                );

            // Create layout operations
            var layoutOperations = new LayoutController <Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >, RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, RoomTemplateInstanceGrid2D, EnergyData>(averageSize, levelDescriptionMapped, constraintsEvaluator, roomShapesHandler, configuration.ThrowIfRepeatModeNotSatisfied, simpleConfigurationSpaces, roomShapeGeometry);

            var initialLayout   = new Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >(levelDescriptionMapped.GetGraph());
            var layoutConverter =
                new BasicLayoutConverterGrid2D <TRoom,
                                                ConfigurationGrid2D <TRoom, EnergyData> >(levelDescription, simpleConfigurationSpaces,
                                                                                          intAliasMapping);

            // Create simulated annealing evolver
            var layoutEvolver =
                new Common.SimulatedAnnealingEvolver <Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >, RoomNode <TRoom>,
                                                      ConfigurationGrid2D <TRoom, EnergyData> >(layoutOperations, configuration.SimulatedAnnealingConfiguration, true);

            // Create the generator itself
            generator = new ChainBasedGenerator <Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >, LayoutGrid2D <TRoom>, RoomNode <TRoom> >(initialLayout, generatorPlanner, chains, layoutEvolver, layoutConverter);

            // Register event handlers
            generator.OnRandomInjected += (random) =>
            {
                // ((IRandomInjectable)configurationSpaces).InjectRandomGenerator(random);
                ((IRandomInjectable)layoutOperations).InjectRandomGenerator(random);
                ((IRandomInjectable)layoutEvolver).InjectRandomGenerator(random);
                ((IRandomInjectable)layoutConverter).InjectRandomGenerator(random);
                ((IRandomInjectable)simpleConfigurationSpaces).InjectRandomGenerator(random);
                ((IRandomInjectable)roomShapesHandler).InjectRandomGenerator(random);
            };

            generator.OnCancellationTokenInjected += (token) =>
            {
                ((ICancellable)generatorPlanner).SetCancellationToken(token);
                ((ICancellable)layoutEvolver).SetCancellationToken(token);
            };

            layoutEvolver.OnEvent              += (sender, args) => OnSimulatedAnnealingEvent?.Invoke(sender, args);
            layoutEvolver.OnPerturbed          += (sender, layout) => OnPerturbed?.Invoke(layoutConverter.Convert(layout, false));
            layoutEvolver.OnPerturbed          += (sender, layout) => OnPerturbedInternal?.Invoke(layout);
            layoutEvolver.OnValid              += (sender, layout) => OnPartialValid?.Invoke(layoutConverter.Convert(layout, true));
            generatorPlanner.OnLayoutGenerated += layout => OnValid?.Invoke(layoutConverter.Convert(layout, true));
        }
 private void PerturbedLayoutsHandler(TLayout layout)
 {
     OnPerturbed?.Invoke(layoutConverter.Convert(layout, false));
 }