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(); }
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(); }
/// <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()); }
/// <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(); }
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(); }
/// <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(); }