示例#1
0
        public TilePropagator(TileModel tileModel, ITopology topology, TilePropagatorOptions options)
        {
            this.tileModel = tileModel;
            this.topology  = topology;

            var overlapping = tileModel as OverlappingModel;

            tileModelMapping = tileModel.GetTileModelMapping(topology);
            var patternTopology = tileModelMapping.PatternTopology;
            var patternModel    = tileModelMapping.PatternModel;

            var waveConstraints =
                (options.Constraints?.Select(x => new TileConstraintAdaptor(x, this)).ToArray() ?? Enumerable.Empty <IWaveConstraint>())
                .ToArray();

            var waveFrequencySets = options.Weights == null ? null : GetFrequencySets(options.Weights, tileModelMapping);

#pragma warning disable CS0618 // Type or member is obsolete
            this.wavePropagator = new WavePropagator(
                patternModel,
                patternTopology,
                options.BackTrackDepth,
                waveConstraints,
                options.RandomDouble ?? (options.Random == null ? (Func <double>)null : options.Random.NextDouble),
                waveFrequencySets,
                clear: false);
#pragma warning restore CS0618 // Type or member is obsolete
            wavePropagator.Clear();
        }
示例#2
0
        public TilePropagator(TileModel tileModel, ITopology topology, TilePropagatorOptions options)
        {
            this.tileModel = tileModel;
            this.topology  = topology;

            var overlapping = tileModel as OverlappingModel;

            tileModelMapping = tileModel.GetTileModelMapping(topology);
            var patternTopology = tileModelMapping.PatternTopology;
            var patternModel    = tileModelMapping.PatternModel;

            var waveConstraints =
                (options.Constraints?.Select(x => new TileConstraintAdaptor(x, this)).ToArray() ?? Enumerable.Empty <IWaveConstraint>())
                .ToArray();


#pragma warning disable CS0618 // Type or member is obsolete
            var randomDouble = options.RandomDouble ?? (options.Random ?? new Random()).NextDouble;
#pragma warning restore CS0618 // Type or member is obsolete

            var(indexPicker, patternPicker) = MakePickers(options);

            var wavePropagatorOptions = new WavePropagatorOptions
            {
                BacktrackPolicy          = MakeBacktrackPolicy(options),
                MaxBacktrackDepth        = options.MaxBacktrackDepth,
                RandomDouble             = randomDouble,
                Constraints              = waveConstraints,
                IndexPicker              = indexPicker,
                PatternPicker            = patternPicker,
                Clear                    = false,
                ModelConstraintAlgorithm = options.ModelConstraintAlgorithm,
            };

            this.wavePropagator = new WavePropagator(
                patternModel,
                patternTopology,
                wavePropagatorOptions);
            wavePropagator.Clear();
        }
示例#3
0
 /// <summary>
 /// Resets the TilePropagator to the state it was in at construction.
 /// </summary>
 /// <returns>The current <see cref="Status"/> (usually <see cref="Resolution.Undecided"/> unless there are very specific initial conditions)</returns>
 public Resolution Clear()
 {
     return(wavePropagator.Clear());
 }
示例#4
0
        /// <summary>
        /// Constructs a TilePropagator.
        /// </summary>
        /// <param name="tileModel">The model to guide the generation.</param>
        /// <param name="topology">The dimensions of the output to generate</param>
        /// <param name="backtrack">If true, store additional information to allow rolling back choices that lead to a contradiction.</param>
        /// <param name="constraints">Extra constraints to control the generation process.</param>
        /// <param name="random">Source of randomness</param>
        public TilePropagator(TileModel tileModel, Topology topology, bool backtrack = false,
                              ITileConstraint[] constraints = null,
                              Random random = null)
        {
            this.tileModel = tileModel;
            this.topology  = topology;

            var overlapping = tileModel as OverlappingModel;

            Topology patternTopology;

            if (!(topology.PeriodicX && topology.PeriodicY && topology.PeriodicZ) && overlapping != null)
            {
                // Shrink the topology as patterns can cover multiple tiles.
                patternTopology = topology.WithSize(
                    topology.PeriodicX ? topology.Width : topology.Width - overlapping.NX + 1,
                    topology.PeriodicY ? topology.Height : topology.Height - overlapping.NY + 1,
                    topology.PeriodicZ ? topology.Depth : topology.Depth - overlapping.NZ + 1);

                mappingType = MappingType.Overlapping;
                mappingNX   = overlapping.NX;
                mappingNY   = overlapping.NY;
                mappingNZ   = overlapping.NZ;

                // Compute tilesToPatterns and patternsToTiles
                var patternArrays = overlapping.PatternArrays;
                tilesToPatternsByOffset = new Dictionary <int, IReadOnlyDictionary <Tile, ISet <int> > >();
                patternsToTilesByOffset = new Dictionary <int, IReadOnlyDictionary <int, Tile> >();
                for (int ox = 0; ox < overlapping.NX; ox++)
                {
                    for (int oy = 0; oy < overlapping.NY; oy++)
                    {
                        for (int oz = 0; oz < overlapping.NZ; oz++)
                        {
                            var o = CombineOffsets(ox, oy, oz);
                            var tilesToPatterns = new Dictionary <Tile, ISet <int> >();
                            tilesToPatternsByOffset[o] = tilesToPatterns;
                            var patternsToTiles = new Dictionary <int, Tile>();
                            patternsToTilesByOffset[o] = patternsToTiles;
                            for (var pattern = 0; pattern < patternArrays.Count; pattern++)
                            {
                                var patternArray = patternArrays[pattern];
                                var tile         = patternArray.Values[ox, oy, oz];
                                patternsToTiles[pattern] = tile;
                                if (!tilesToPatterns.TryGetValue(tile, out var patternSet))
                                {
                                    patternSet = tilesToPatterns[tile] = new HashSet <int>();
                                }
                                patternSet.Add(pattern);
                            }
                        }
                    }
                }
            }
            else
            {
                patternTopology         = topology;
                mappingType             = MappingType.OneToOne;
                tilesToPatternsByOffset = new Dictionary <int, IReadOnlyDictionary <Tile, ISet <int> > >()
                {
                    { 0, tileModel.TilesToPatterns.ToDictionary(g => g.Key, g => (ISet <int>) new HashSet <int>(g)) }
                };
                patternsToTilesByOffset = new Dictionary <int, IReadOnlyDictionary <int, Tile> >
                {
                    { 0, tileModel.PatternsToTiles },
                };
            }

            // Masks interact a bit weirdly with the overlapping model
            // We choose a pattern mask that is a expansion of the topology mask
            // i.e. a pattern location is masked out if all the tile locations it covers is masked out.
            // This makes the propagator a bit conservative - it'll always preserve the overlapping property
            // but might ban some layouts that make sense.
            // The alternative is to contract the mask - that is more permissive, but sometimes will
            // violate the overlapping property.
            // (passing the mask verbatim is unacceptable as does not lead to symmetric behaviour)
            // See TestTileMaskWithThinOverlapping for an example of the problem, and
            // https://github.com/BorisTheBrave/DeBroglie/issues/7 for a possible solution.
            if (topology.Mask != null && overlapping != null)
            {
                // TODO: This could probably do with some cleanup
                bool GetTopologyMask(int x, int y, int z)
                {
                    if (!topology.PeriodicX && x >= topology.Width)
                    {
                        return(false);
                    }
                    if (!topology.PeriodicY && y >= topology.Height)
                    {
                        return(false);
                    }
                    if (!topology.PeriodicZ && z >= topology.Depth)
                    {
                        return(false);
                    }
                    x = x % topology.Width;
                    y = y % topology.Height;
                    z = z % topology.Depth;
                    return(topology.Mask[topology.GetIndex(x, y, z)]);
                }

                bool GetPatternTopologyMask(Point p)
                {
                    for (var oz = 0; oz < overlapping.NZ; oz++)
                    {
                        for (var oy = 0; oy < overlapping.NY; oy++)
                        {
                            for (var ox = 0; ox < overlapping.NX; ox++)
                            {
                                if (GetTopologyMask(p.X + ox, p.Y + oy, p.Z + oz))
                                {
                                    return(true);
                                }
                            }
                        }
                    }
                    return(false);
                }

                var patternMask = TopoArray.Create(GetPatternTopologyMask, patternTopology);
                patternTopology = patternTopology.WithMask(patternMask);
            }

            var waveConstraints =
                (constraints?.Select(x => new TileConstraintAdaptor(x, this)).ToArray() ?? Enumerable.Empty <IWaveConstraint>())
                .ToArray();

            this.wavePropagator = new WavePropagator(tileModel.GetPatternModel(), patternTopology, backtrack, waveConstraints, random, clear: false);
            wavePropagator.Clear();
        }
示例#5
0
        public TilePropagator(TileModel tileModel, ITopology topology, TilePropagatorOptions options)
        {
            this.tileModel = tileModel;
            this.topology  = topology;

            var overlapping = tileModel as OverlappingModel;

            tileModelMapping = tileModel.GetTileModelMapping(topology);
            var patternTopology = tileModelMapping.PatternTopology;
            var patternModel    = tileModelMapping.PatternModel;

            var waveConstraints =
                (options.Constraints?.Select(x => new TileConstraintAdaptor(x, this)).ToArray() ?? Enumerable.Empty <IWaveConstraint>())
                .ToArray();

            var waveFrequencySets = options.Weights == null ? null : GetFrequencySets(options.Weights, tileModelMapping);

#pragma warning disable CS0618 // Type or member is obsolete
            var randomDouble = options.RandomDouble ?? (options.Random ?? new Random()).NextDouble;
#pragma warning restore CS0618 // Type or member is obsolete

            IPickHeuristic MakePickHeuristic(WavePropagator wavePropagator)
            {
                IRandomPicker randomPicker;

                if (options.PickHeuristicType == PickHeuristicType.Ordered)
                {
                    randomPicker = new OrderedRandomPicker(wavePropagator.Wave, wavePropagator.Frequencies, patternTopology.Mask);
                }
                else if (waveFrequencySets != null)
                {
                    var entropyTracker = new ArrayPriorityEntropyTracker(wavePropagator.Wave, waveFrequencySets, patternTopology.Mask);
                    entropyTracker.Reset();
                    wavePropagator.AddTracker(entropyTracker);
                    randomPicker = entropyTracker;
                }
                else
                {
                    var entropyTracker = new EntropyTracker(wavePropagator.Wave, wavePropagator.Frequencies, patternTopology.Mask);
                    entropyTracker.Reset();
                    wavePropagator.AddTracker(entropyTracker);
                    randomPicker = entropyTracker;
                }
                IPickHeuristic heuristic = new RandomPickerHeuristic(randomPicker, randomDouble);

                var pathConstraint = options.Constraints?.OfType <EdgedPathConstraint>().FirstOrDefault();

                if (pathConstraint != null && pathConstraint.UsePickHeuristic)
                {
                    heuristic = pathConstraint.GetHeuristic(
                        randomPicker,
                        randomDouble,
                        this,
                        tileModelMapping,
                        heuristic);
                }

                var connectedConstraint = options.Constraints?.OfType <ConnectedConstraint>().FirstOrDefault();

                if (connectedConstraint != null && connectedConstraint.UsePickHeuristic)
                {
                    heuristic = connectedConstraint.GetHeuristic(
                        randomPicker,
                        randomDouble,
                        this,
                        tileModelMapping,
                        heuristic);
                }

                return(heuristic);
            }

            var wavePropagatorOptions = new WavePropagatorOptions
            {
                BackTrackDepth       = options.BackTrackDepth,
                RandomDouble         = randomDouble,
                Constraints          = waveConstraints,
                PickHeuristicFactory = MakePickHeuristic,
                Clear = false,
                ModelConstraintAlgorithm = options.ModelConstraintAlgorithm,
            };

            this.wavePropagator = new WavePropagator(
                patternModel,
                patternTopology,
                wavePropagatorOptions);
            wavePropagator.Clear();
        }
示例#6
0
        /// <summary>
        /// Constructs a TilePropagator.
        /// </summary>
        /// <param name="tileModel">The model to guide the generation.</param>
        /// <param name="topology">The dimensions of the output to generate</param>
        /// <param name="backtrack">If true, store additional information to allow rolling back choices that lead to a contradiction.</param>
        /// <param name="constraints">Extra constraints to control the generation process.</param>
        /// <param name="random">Source of randomness</param>
        public TilePropagator(TileModel tileModel, Topology topology, bool backtrack = false,
                              ITileConstraint[] constraints = null,
                              Random random = null)
        {
            this.tileModel = tileModel;
            this.topology  = topology;

            var patternTopology = topology;

            if (!(topology.PeriodicX && topology.PeriodicY && topology.PeriodicZ) && tileModel is OverlappingModel overlapping)
            {
                // Shrink the topology as patterns can cover multiple tiles.
                patternTopology = topology.WithSize(
                    topology.PeriodicX ? topology.Width : topology.Width - overlapping.NX + 1,
                    topology.PeriodicY ? topology.Height : topology.Height - overlapping.NY + 1,
                    topology.PeriodicZ ? topology.Depth : topology.Depth - overlapping.NZ + 1);

                mappingType = MappingType.Overlapping;
                mappingNX   = overlapping.NX;
                mappingNY   = overlapping.NY;
                mappingNZ   = overlapping.NZ;

                // Compute tilesToPatterns and patternsToTiles
                var patternArrays = overlapping.PatternArrays;
                tilesToPatternsByOffset = new Dictionary <int, IReadOnlyDictionary <Tile, ISet <int> > >();
                patternsToTilesByOffset = new Dictionary <int, IReadOnlyDictionary <int, Tile> >();
                for (int ox = 0; ox < overlapping.NX; ox++)
                {
                    for (int oy = 0; oy < overlapping.NY; oy++)
                    {
                        for (int oz = 0; oz < overlapping.NZ; oz++)
                        {
                            var o = CombineOffsets(ox, oy, oz);
                            var tilesToPatterns = new Dictionary <Tile, ISet <int> >();
                            tilesToPatternsByOffset[o] = tilesToPatterns;
                            var patternsToTiles = new Dictionary <int, Tile>();
                            patternsToTilesByOffset[o] = patternsToTiles;
                            for (var pattern = 0; pattern < patternArrays.Count; pattern++)
                            {
                                var patternArray = patternArrays[pattern];
                                var tile         = patternArray.Values[ox, oy, oz];
                                patternsToTiles[pattern] = tile;
                                if (!tilesToPatterns.TryGetValue(tile, out var patternSet))
                                {
                                    patternSet = tilesToPatterns[tile] = new HashSet <int>();
                                }
                                patternSet.Add(pattern);
                            }
                        }
                    }
                }
            }
            else
            {
                mappingType             = MappingType.OneToOne;
                tilesToPatternsByOffset = new Dictionary <int, IReadOnlyDictionary <Tile, ISet <int> > >()
                {
                    { 0, tileModel.TilesToPatterns.ToDictionary(g => g.Key, g => (ISet <int>) new HashSet <int>(g)) }
                };
                patternsToTilesByOffset = new Dictionary <int, IReadOnlyDictionary <int, Tile> >
                {
                    { 0, tileModel.PatternsToTiles },
                };
            }

            var waveConstraints =
                (constraints?.Select(x => new TileConstraintAdaptor(x, this)).ToArray() ?? Enumerable.Empty <IWaveConstraint>())
                .ToArray();

            this.wavePropagator = new WavePropagator(tileModel.GetPatternModel(), patternTopology, backtrack, waveConstraints, random, clear: false);
            wavePropagator.Clear();
        }