public void TestMemoizeIndices() { var model = new PatternModel { Frequencies = new double[] { 1, 1 }, // Free model Propagator = new int[][][] { new int[][] { new int[] { 0, 1 }, new int[] { 0, 1 }, new int[] { 0, 1 }, new int[] { 0, 1 }, }, new int[][] { new int[] { 0, 1 }, new int[] { 0, 1 }, new int[] { 0, 1 }, new int[] { 0, 1 }, }, } }; var width = 10; var height = 10; var topology = new GridTopology(width, height, true); var indexPicker = new CustomIndexPicker(); var memoIndexPicker = new MemoizeIndexPicker(indexPicker); var options = new WavePropagatorOptions { BacktrackPolicy = new ConstantBacktrackPolicy(1), IndexPicker = memoIndexPicker, PatternPicker = new SimpleOrderedPatternPicker(), Constraints = new[] { new DontBanOneConstraint() }, }; var propagator = new WavePropagator(model, topology, options); // Attempts to pick pattern 0 at index 0, should contradict and backtrack var status = propagator.Step(); Assert.AreEqual(Resolution.Undecided, status); Assert.AreEqual(1, propagator.BacktrackCount); CollectionAssert.AreEqual(propagator.GetPossiblePatterns(0), new[] { 1 }); Assert.AreEqual(1, indexPicker.Count); // Should re-attempt index zero, with no effect. propagator.Step(); Assert.AreEqual(Resolution.Undecided, status); Assert.AreEqual(1, propagator.BacktrackCount); CollectionAssert.AreEqual(propagator.GetPossiblePatterns(0), new[] { 1 }); Assert.AreEqual(1, indexPicker.Count); // Attempts to pick pattern 0 at index 1, should contradict and backtrack propagator.Step(); Assert.AreEqual(Resolution.Undecided, status); Assert.AreEqual(2, propagator.BacktrackCount); CollectionAssert.AreEqual(propagator.GetPossiblePatterns(1), new[] { 1 }); Assert.AreEqual(2, indexPicker.Count); // etc }
private Tuple <IIndexPicker, IPatternPicker> MakePickers(TilePropagatorOptions options) { var pathConstraint = options.Constraints?.OfType <EdgedPathConstraint>().FirstOrDefault(); var connectedConstraint = options.Constraints?.OfType <ConnectedConstraint>().FirstOrDefault(); var connectedPickHeuristic = connectedConstraint != null && connectedConstraint.UsePickHeuristic; if (connectedPickHeuristic) { // Lists pickers that implement IFilteredIndexPicker if (options.IndexPickerType != IndexPickerType.Default && options.IndexPickerType != IndexPickerType.MinEntropy && options.IndexPickerType != IndexPickerType.Ordered) { throw new Exception($"Connected Pick Heuristic is incompatible with the selected IndexPikcerType {options.IndexPickerType}"); } if (options.IndexPickerType == IndexPickerType.Default) { options.IndexPickerType = IndexPickerType.MinEntropy; } } // Use the appropriate random picker // Generally this is HeapEntropyTracker, but it doesn't support some features // so there's a few slower implementations for that IIndexPicker indexPicker = null; IPatternPicker patternPicker = null; switch (options.IndexPickerType) { case IndexPickerType.Ordered: { if (options.IndexOrder != null) { indexPicker = new OrderedIndexPicker(options.IndexOrder); } else { indexPicker = new SimpleOrderedIndexPicker(); } break; } case IndexPickerType.ArrayPriorityMinEntropy: { if (options.WeightSetByIndex == null || options.WeightSets == null) { throw new ArgumentNullException($"Expected WeightSetByIndex and WeightSets to be set"); } if (options.TilePickerType != TilePickerType.ArrayPriority && options.TilePickerType != TilePickerType.Default) { throw new Exception($"ArrayPriorityMinEntropy only works with Default tile picker"); } var weightSetCollection = new WeightSetCollection(options.WeightSetByIndex, options.WeightSets, tileModelMapping); var entropyTracker = new ArrayPriorityEntropyTracker(weightSetCollection); indexPicker = entropyTracker; patternPicker = entropyTracker; break; } case IndexPickerType.MinEntropy: { indexPicker = new EntropyTracker(); break; } case IndexPickerType.Default: case IndexPickerType.HeapMinEntropy: { indexPicker = new HeapEntropyTracker(); break; } case IndexPickerType.Dirty: { // Create clean patterns if (tileModelMapping.TileCoordToPatternCoordIndexAndOffset != null) { throw new NotSupportedException(); } if (options.CleanTiles == null) { throw new ArgumentNullException($"{nameof(options.CleanTiles)} is null"); } var cleanPatterns = options.CleanTiles.Map(t => tileModelMapping.TilesToPatternsByOffset[0][t].First()); indexPicker = new DirtyIndexPicker(new SimpleOrderedIndexPicker(), cleanPatterns); break; } default: throw new Exception($"Unknown IndexPickerType {options.IndexPickerType}"); } if (patternPicker == null) { switch (options.TilePickerType) { case TilePickerType.Default: case TilePickerType.Weighted: patternPicker = new WeightedRandomPatternPicker(); break; case TilePickerType.Ordered: patternPicker = new SimpleOrderedPatternPicker(); break; case TilePickerType.ArrayPriority: if (options.WeightSetByIndex == null || options.WeightSets == null) { throw new ArgumentNullException($"Expected WeightSetByIndex and WeightSets to be set"); } var weightSetCollection = new WeightSetCollection(options.WeightSetByIndex, options.WeightSets, tileModelMapping); patternPicker = new ArrayPriorityPatternPicker(weightSetCollection); break; default: throw new Exception($"Unknown TilePickerType {options.TilePickerType}"); } } if (connectedPickHeuristic) { indexPicker = connectedConstraint.GetHeuristic( (IFilteredIndexPicker)indexPicker, this); } if (options.MemoizeIndices) { indexPicker = new MemoizeIndexPicker(indexPicker); } return(Tuple.Create(indexPicker, patternPicker)); }