private void AssertRuleDoesNotMatchCondtitional( string ruleText, int[] sourceSymbols = null, float[][] sourceParameters = null, string axiom = null, int ruleParamMemoryStartIndex = 0, int matchIndex = 0, int paramTempMemorySize = 0, float[] globalParams = null, string[] globalParamNames = null, string includedSymbols = "[]ABCDE" ) { var totalIncluded = new HashSet <int>(includedSymbols.Select(x => (int)x)); globalParamNames = globalParamNames ?? new string[0]; using var symbols = new DependencyTracker <SymbolString <float> >( axiom == null ? new SymbolString <float>(sourceSymbols, sourceParameters) : SymbolString <float> .FromString(axiom, Allocator.Persistent) ); var ruleFromString = new BasicRule( RuleParser.ParseToRule(ruleText, x => x, globalParameters: globalParamNames), '[', ']'); using var ruleNativeData = new SystemLevelRuleNativeData(new[] { ruleFromString }); var nativeWriter = new SymbolSeriesMatcherNativeDataWriter(); ruleFromString.WriteDataIntoMemory(ruleNativeData, nativeWriter); globalParams = globalParams ?? new float[0]; using var globalNative = new NativeArray <float>(globalParams, Allocator.Persistent); using var paramMemory = new NativeArray <float>(paramTempMemorySize, Allocator.Persistent); using var branchCache = new SymbolStringBranchingCache('[', ']', new[] { totalIncluded }, ruleNativeData); branchCache.BuildJumpIndexesFromSymbols(symbols); var random = new Unity.Mathematics.Random(); var matchSingleData = new LSystemSingleSymbolMatchData { isTrivial = false, tmpParameterMemorySpace = JaggedIndexing.GetWithNoLength(ruleParamMemoryStartIndex) }; var potentialMatch = ruleFromString.AsBlittable().PreMatchCapturedParametersWithoutConditional( branchCache, symbols.Data, matchIndex, paramMemory, matchSingleData.tmpParameterMemorySpace.index, ref matchSingleData, new TmpNativeStack <SymbolStringBranchingCache.BranchEventData>(5), globalNative, ruleNativeData.dynamicOperatorMemory, ref random, ruleNativeData.ruleOutcomeMemorySpace ); Assert.IsFalse(potentialMatch); }
public static IEnumerable <BasicRule> CompileAndCheckParsedRules( ParsedRule[] parsedRules, out SystemLevelRuleNativeData ruleNativeData, int branchOpenSymbol, int branchCloseSymbol) { var basicRules = parsedRules.Where(r => !(r is ParsedStochasticRule)) .Select(x => new BasicRule(x, branchOpenSymbol, branchCloseSymbol)).ToList(); IEqualityComparer <ParsedRule> ruleComparer = new ParsedRuleEqualityComparer(); #if UNITY_EDITOR for (int i = 0; i < parsedRules.Length; i++) { if (parsedRules[i] is ParsedStochasticRule) { continue; } for (int j = i + 1; j < parsedRules.Length; j++) { if (parsedRules[j] is ParsedStochasticRule) { continue; } if (ruleComparer.Equals(parsedRules[i], parsedRules[j])) { throw new LSystemRuntimeException($"Cannot have two non-stochastic rules matching the same symbols. matching rules: {parsedRules[i]} {parsedRules[j]}"); } } } #endif var stochasticRules = parsedRules.Where(r => r is ParsedStochasticRule) .Select(x => x as ParsedStochasticRule) .GroupBy(x => x, ruleComparer) .Select(group => { var probabilityDeviation = System.Math.Abs(group.Sum(x => x.probability) - 1); if (probabilityDeviation > 1e-5) { throw new LSystemRuntimeException($"Error: probability is {probabilityDeviation} away from 1 in rule group {group.Key.TargetSymbolString()}"); } return(new BasicRule(group, branchOpenSymbol, branchCloseSymbol)); }).ToList(); var allRules = basicRules.Concat(stochasticRules).ToArray(); ruleNativeData = new SystemLevelRuleNativeData(allRules); var nativeWriter = new SymbolSeriesMatcherNativeDataWriter(); foreach (var rule in allRules) { rule.WriteDataIntoMemory(ruleNativeData, nativeWriter); } return(allRules); }
private void AssertBackwardsMatch( string target, string matcher, bool shouldMatch, string includeSymbols = "[]ABCDEFJ", int parameterMemorySize = 10, float[] expectedCapturedParameters = null, int indexInTarget = -1) { var includedSymbolSet = includeSymbols.Select(x => (int)x); var prefixBuilder = SymbolSeriesPrefixBuilder.Parse(matcher); using var nativeData = new SystemLevelRuleNativeData(new RuleDataRequirements { prefixNodes = prefixBuilder.RequiredNodeMemorySpace }); var writer = new SymbolSeriesMatcherNativeDataWriter(); var seriesMatcher = prefixBuilder.BuildIntoManagedMemory(nativeData, writer); using var targetString = new DependencyTracker <SymbolString <float> >(SymbolString <float> .FromString(target)); using var branchingCache = new SymbolStringBranchingCache( '[', ']', includedSymbolSet == null ? new HashSet <int> [0] : new[] { new HashSet <int>(includedSymbolSet) }, nativeData); branchingCache.BuildJumpIndexesFromSymbols(targetString); using var parameterMemory = new NativeArray <float>(parameterMemorySize, Allocator.Persistent); var realIndex = indexInTarget < 0 ? indexInTarget + targetString.Data.Length : indexInTarget; var hasMatched = branchingCache.MatchesBackwards( branchingCache.includeSymbols[0], realIndex, seriesMatcher, targetString.Data, 0, parameterMemory, out var copiedParams); if (shouldMatch != hasMatched) { Assert.Fail($"Expected '{matcher}' to {(shouldMatch ? "" : "not ")}match backwards from {indexInTarget} in '{target}'"); } if (shouldMatch && expectedCapturedParameters != null) { Assert.AreEqual(expectedCapturedParameters.Length, copiedParams); for (int i = 0; i < expectedCapturedParameters.Length; i++) { Assert.AreEqual(expectedCapturedParameters[i], parameterMemory[i]); } } }
public static SymbolSeriesSuffixMatcher GenerateSingleMatcher( string matchPattern, out SystemLevelRuleNativeData nativeData) { var builder = SymbolSeriesSuffixBuilder.Parse(matchPattern); builder.BuildGraphIndexes('[', ']'); nativeData = new SystemLevelRuleNativeData(new RuleDataRequirements { suffixChildren = builder.RequiredChildrenMemSpace, suffixGraphNodes = builder.RequiredGraphNodeMemSpace }); var writer = new SymbolSeriesMatcherNativeDataWriter(); return(builder.BuildIntoManagedMemory(nativeData, writer)); }
public void BasicRuleRejectsApplicationIfAnyParameters() { var ruleFromString = new BasicRule( RuleParser.ParseToRule("A -> AB", x => x), '[', ']'); var totalIncluded = new HashSet <int>("[]AB".Select(x => (int)x)); using var ruleNativeData = new SystemLevelRuleNativeData(new[] { ruleFromString }); var nativeWriter = new SymbolSeriesMatcherNativeDataWriter(); ruleFromString.WriteDataIntoMemory(ruleNativeData, nativeWriter); var symbols = new DependencyTracker <SymbolString <float> >( new SymbolString <float>(new int[] { 'A' }, new float[][] { new float[0] }) ); try { var globalParams = new float[0]; using var globalNative = new NativeArray <float>(globalParams, Allocator.Persistent); using var paramMemory = new NativeArray <float>(0, Allocator.Persistent); using var branchCache = new SymbolStringBranchingCache('[', ']', new[] { totalIncluded }, ruleNativeData); branchCache.BuildJumpIndexesFromSymbols(symbols); var random = new Unity.Mathematics.Random(); var matchSingleData = new LSystemSingleSymbolMatchData { isTrivial = false, tmpParameterMemorySpace = JaggedIndexing.GetWithNoLength(0) }; var preMatchSuccess = ruleFromString.AsBlittable().PreMatchCapturedParametersWithoutConditional( branchCache, symbols.Data, 0, paramMemory, matchSingleData.tmpParameterMemorySpace.index, ref matchSingleData, new TmpNativeStack <SymbolStringBranchingCache.BranchEventData>(5), globalNative, ruleNativeData.dynamicOperatorMemory, ref random, ruleNativeData.ruleOutcomeMemorySpace ); Assert.IsTrue(preMatchSuccess); Assert.AreEqual(0, matchSingleData.selectedReplacementPattern); Assert.AreEqual(0, matchSingleData.tmpParameterMemorySpace.length); Assert.AreEqual(2, matchSingleData.replacementSymbolIndexing.length); Assert.AreEqual(0, matchSingleData.replacementParameterIndexing.length); var symbolRawData = symbols.Data; symbolRawData.parameters[0] = new JaggedIndexing { index = 0, length = 1 }; matchSingleData = new LSystemSingleSymbolMatchData { isTrivial = false, tmpParameterMemorySpace = JaggedIndexing.GetWithNoLength(0) }; preMatchSuccess = ruleFromString.AsBlittable().PreMatchCapturedParametersWithoutConditional( branchCache, symbols.Data, 0, paramMemory, matchSingleData.tmpParameterMemorySpace.index, ref matchSingleData, new TmpNativeStack <SymbolStringBranchingCache.BranchEventData>(5), globalNative, ruleNativeData.dynamicOperatorMemory, ref random, ruleNativeData.ruleOutcomeMemorySpace ); Assert.IsFalse(preMatchSuccess); } finally { symbols.Dispose(); } }