public void TestTrueFalse() { var tree = new TriggerTree(); tree.AddTrigger("exists(blah) && true", 1); tree.AddTrigger("exists(blah) && false", 2); tree.AddTrigger("exists(blah)", 3); tree.AddTrigger("true", 4); tree.AddTrigger("false", 5); var memory = new Dictionary <string, object>(); var matches = tree.Matches(memory).ToList(); Assert.AreEqual(1, matches.Count); var triggers = matches[0].Triggers; Assert.AreEqual(1, triggers.Count); Assert.AreEqual(4, triggers[0].Action); memory.Add("blah", 1); matches = tree.Matches(memory).ToList(); Assert.AreEqual(1, matches.Count()); triggers = matches[0].Triggers; Assert.AreEqual(2, triggers.Count); Assert.AreEqual(1, triggers[0].Action); Assert.AreEqual(3, triggers[1].Action); }
public void TestRoot() { var tree = new TriggerTree(); tree.AddTrigger("true", "root"); var matches = tree.Matches(new Dictionary <string, object>()); Assert.AreEqual(1, matches.Count()); Assert.AreEqual("root", matches.First().Action); }
public void TestOr() { var tree = new TriggerTree(); tree.AddTrigger("exists(woof) || exists(blah)", 1); tree.AddTrigger("exists(blah)", 2); tree.AddTrigger("exists(blah) && exists(foo)", 3); var frame = new Dictionary <string, object> { { "blah", 1 }, { "woof", 3 } }; var matches = tree.Matches(frame).ToList(); Assert.AreEqual(2, matches.Count); Assert.AreEqual(1, matches[0].Action); Assert.AreEqual(2, matches[1].Action); }
public void TestIgnore() { var tree = new TriggerTree(); tree.AddTrigger("ignore(!exists(foo)) && exists(blah)", 1); tree.AddTrigger("exists(blah) && ignore(!exists(foo2)) && woof == 3", 2); tree.AddTrigger("exists(blah) && woof == 3", 3); tree.AddTrigger("exists(blah) && woof == 3 && ignore(!exists(foo2))", 2); var frame = new Dictionary <string, object> { { "blah", 1 }, { "woof", 3 } }; var matches = tree.Matches(frame).ToList(); Assert.Equal(2, matches.Count); Assert.Equal(2, matches[0].Action); Assert.Equal(3, matches[1].Action); }
/// <summary> /// Selects the best rule to execute. /// </summary> /// <param name="context">The <see cref="DialogContext"/> for the current turn of conversation.</param> /// <param name="cancellationToken">Optional, <see cref="CancellationToken"/> of the task.</param> /// <returns>Best rule in original list to execute or -1 if none.</returns> public override async Task <IReadOnlyList <OnCondition> > SelectAsync(ActionContext context, CancellationToken cancellationToken) { var triggers = _tree.Matches(context.State); var matches = new List <OnCondition>(); foreach (var trigger in triggers) { matches.Add(trigger.Action as OnCondition); } IReadOnlyList <OnCondition> selections = matches; if (matches.Count > 0 && Selector != null) { Selector.Initialize(matches, false); selections = await Selector.SelectAsync(context, cancellationToken).ConfigureAwait(false); } return(selections); }
public virtual async Task <IReadOnlyList <OnCondition> > Select(SequenceContext context, CancellationToken cancel) { var triggers = _tree.Matches(context.GetState()); var matches = new List <OnCondition>(); foreach (var trigger in triggers) { matches.Add(trigger.Action as OnCondition); } IReadOnlyList <OnCondition> selections = matches; if (Selector != null) { Selector.Initialize(matches, false); selections = await Selector.Select(context, cancel).ConfigureAwait(false); } return(selections); }
public async Task <IReadOnlyList <int> > Select(SequenceContext context, CancellationToken cancel) { var nodes = _tree.Matches(context.State); IReadOnlyList <int> selections; if (Selector == null) { // Return all matches var matches = new List <int>(); foreach (var node in nodes) { foreach (var trigger in node.AllTriggers) { var(pos, rule) = (ValueTuple <int, OnCondition>)trigger.Action; matches.Add(pos); } } selections = matches; } else { var matches = new List <ValueTuple <int, OnCondition> >(); foreach (var node in nodes) { foreach (var trigger in node.AllTriggers) { matches.Add((ValueTuple <int, OnCondition>)trigger.Action); } } // Sort rules by original order and then pass to child selector matches = (from candidate in matches orderby candidate.Item1 ascending select candidate).ToList(); Selector.Initialize(matches.Select(m => m.Item2), false); selections = (from match in await Selector.Select(context, cancel).ConfigureAwait(false) select matches[match].Item1).ToList(); } return(selections); }
public void TestTree() { var numPredicates = 100; var numSingletons = 50; var numConjunctions = 100; var numDisjunctions = 100; var numOptionals = 100; var numQuantifiers = 100; var numNots = 100; var minClause = 2; var maxClause = 4; var maxExpansion = 3; var maxQuantifiers = 3; var singletons = _generator.GeneratePredicates(numPredicates, "mem"); var tree = new TriggerTree(); var predicates = new List <ExpressionInfo>(singletons); var triggers = new List <Trigger>(); // Add singletons foreach (var predicate in singletons.Take(numSingletons)) { triggers.Add(tree.AddTrigger(predicate.Expression, predicate.Bindings)); } Assert.AreEqual(numSingletons, tree.TotalTriggers); // Add conjunctions and test matches var conjunctions = _generator.GenerateConjunctions(predicates, numConjunctions, minClause, maxClause); foreach (var conjunction in conjunctions) { var memory = new Dictionary <string, object>(); foreach (var binding in conjunction.Bindings) { memory.Add(binding.Key, binding.Value.Value); } var trigger = tree.AddTrigger(conjunction.Expression, conjunction.Bindings); var matches = tree.Matches(memory); triggers.Add(trigger); Assert.IsTrue(matches.Count() >= 1); var first = matches.First().Clauses.First(); foreach (var match in matches) { Assert.AreEqual(RelationshipType.Equal, first.Relationship(match.Clauses.First(), tree.Comparers)); } } Assert.AreEqual(numSingletons + numConjunctions, tree.TotalTriggers); // Add disjunctions predicates.AddRange(conjunctions); var disjunctions = _generator.GenerateDisjunctions(predicates, numDisjunctions, minClause, maxClause); foreach (var disjunction in disjunctions) { triggers.Add(tree.AddTrigger(disjunction.Expression, disjunction.Bindings)); } Assert.AreEqual(numSingletons + numConjunctions + numDisjunctions, tree.TotalTriggers); var all = new List <ExpressionInfo>(predicates); all.AddRange(disjunctions); // Add optionals var optionals = _generator.GenerateOptionals(all, numOptionals, minClause, maxClause); foreach (var optional in optionals) { triggers.Add(tree.AddTrigger(optional.Expression, optional.Bindings)); } Assert.AreEqual(numSingletons + numConjunctions + numDisjunctions + numOptionals, tree.TotalTriggers); all.AddRange(optionals); // Add quantifiers var quantified = _generator.GenerateQuantfiers(all, numQuantifiers, maxClause, maxExpansion, maxQuantifiers); foreach (var expr in quantified) { triggers.Add(tree.AddTrigger(expr.Expression, expr.Bindings, expr.Quantifiers.ToArray())); } Assert.AreEqual(numSingletons + numConjunctions + numDisjunctions + numOptionals + numQuantifiers, tree.TotalTriggers); all.AddRange(quantified); var nots = _generator.GenerateNots(all, numNots); foreach (var expr in nots) { triggers.Add(tree.AddTrigger(expr.Expression, expr.Bindings, expr.Quantifiers.ToArray())); } Assert.AreEqual(numSingletons + numConjunctions + numDisjunctions + numOptionals + numQuantifiers + numNots, tree.TotalTriggers); all.AddRange(nots); VerifyTree(tree); // Test matches foreach (var predicate in predicates) { var memory = new Dictionary <string, object>(); foreach (var binding in predicate.Bindings) { memory.Add(binding.Key, binding.Value.Value); } var matches = tree.Matches(memory).ToList(); // Clauses in every match must not generalize or specialize other matches for (var i = 0; i < matches.Count; ++i) { var first = matches[i]; for (var j = i + 1; j < matches.Count; ++j) { var second = matches[j]; var found = false; foreach (var firstClause in first.Clauses) { var(match, error) = firstClause.TryEvaluate <bool>(memory); if (error == null && match) { foreach (var secondClause in second.Clauses) { bool match2; (match2, error) = firstClause.TryEvaluate <bool>(memory); if (error == null && match2) { var reln = firstClause.Relationship(secondClause, tree.Comparers); if (reln == RelationshipType.Equal || reln == RelationshipType.Incomparable) { found = true; break; } } } if (found) { break; } } } Assert.IsTrue(found); } } } // NOTE: This is useful to test tree visualization, but not really a test. // tree.GenerateGraph("tree.dot"); // Delete triggers Assert.AreEqual(triggers.Count, tree.TotalTriggers); foreach (var trigger in triggers) { tree.RemoveTrigger(trigger); } Assert.AreEqual(0, tree.TotalTriggers); VerifyTree(tree); }