public Combinator(MatchedVariables variables, IList <Predicate> predicates, IList <Expression> expressions, HashSet <Fact> allFacts) { this.variables = variables; this.expressions = expressions; this.allFacts = allFacts; this.currentIt = null; this.pred = predicates.FirstOrDefault(); this.fit = allFacts.Where(fact => fact.MatchPredicate(this.pred)).GetEnumerator(); this.nextPredicates = predicates.Skip(1).ToList(); }
// do not produce new facts, only find one matching set of facts public bool Test(HashSet <Fact> facts) { HashSet <ulong> variables_set = new HashSet <ulong>(); foreach (Predicate pred in this.Body) { variables_set.AddAll(pred.Ids.Where((id) => id is ID.Variable).Select(id => ((ID.Variable)id).Value)); } MatchedVariables variables = new MatchedVariables(variables_set); if (!this.Body.Any()) { return(variables.CheckExpressions(this.Expressions).IsDefined); } Combinator c = new Combinator(variables, this.Body, this.Expressions, facts); return(c.Next().IsDefined); }
public Option <MatchedVariables> Next() { bool hasNext = true; while (hasNext) { if (this.currentIt == null) { // we iterate over the facts that match the current predicate if (this.fit.MoveNext()) { Fact currentFact = this.fit.Current; // create a new MatchedVariables in which we fix variables we could unify from our first predicate and the current fact MatchedVariables vars = this.variables.Clone(); bool match_ids = true; // we know the fact matches the predicate's format so they have the same number of terms // fill the MatchedVariables before creating the next combinator for (int i = 0; i < pred.Ids.Count && match_ids; ++i) { ID id = pred.Ids[i]; if (id is ID.Variable idVariable) { ulong key = idVariable.Value; ID value = currentFact.Predicate.Ids[i]; if (!vars.Insert(key, value)) { match_ids = false; } } } if (match_ids) { // there are no more predicates to check if (!nextPredicates.Any()) { Option <Dictionary <ulong, ID> > v_opt = vars.CheckExpressions(this.expressions); if (v_opt.IsDefined) { return(Option <MatchedVariables> .Some(vars)); } } else { // we found a matching fact, we create a new combinator over the rest of the predicates // no need to copy all of the expressions at all levels this.currentIt = new Combinator(vars, nextPredicates, new List <Expression>(), this.allFacts); } } } else { hasNext = false; } } else { Option <MatchedVariables> nextVarsOpt = this.currentIt.Next(); // the iterator is empty, try with the next fact if (nextVarsOpt.IsDefined) { MatchedVariables nextVars = nextVarsOpt.Get(); Option <Dictionary <ulong, ID> > v_opt = nextVars.CheckExpressions(this.expressions); if (v_opt.IsDefined) { return(Option <MatchedVariables> .Some(nextVars)); } } else { this.currentIt = null; } } } return(Option <MatchedVariables> .None()); }
public void Apply(HashSet <Fact> facts, HashSet <Fact> newFacts, HashSet <ulong> restrictedSymbols) { HashSet <ulong> variablesSet = new HashSet <ulong>(); foreach (Predicate pred in this.Body) { variablesSet.AddAll(pred.Ids.Where(id => id is ID.Variable).Select(id => ((ID.Variable)id).Value)); } MatchedVariables variables = new MatchedVariables(variablesSet); if (!this.Body.Any()) { Option <Dictionary <ulong, ID> > h_opt = variables.CheckExpressions(this.Expressions); if (h_opt.IsDefined) { Dictionary <ulong, ID> h = h_opt.Get(); Predicate predicate = this.Head.Clone(); for (int i = 0; i < predicate.Ids.Count; i++) { ID id = predicate.Ids[i]; if (id is ID.Variable) { ID value = h[((ID.Variable)id).Value]; predicate.Ids[i] = value; } } newFacts.Add(new Fact(predicate)); } } var combined = new Combinator(variables, this.Body, this.Expressions, facts).Combine(); foreach (Dictionary <ulong, ID> h in combined) { Predicate predicate = this.Head.Clone(); bool unbound_variable = false; for (int i = 0; i < predicate.Ids.Count; i++) { ID id = predicate.Ids[i]; if (id is ID.Variable) { bool isInDictionnary = h.TryGetValue(((ID.Variable)id).Value, out ID value); predicate.Ids[i] = value; // variables that appear in the head should appear in the body and constraints as well if (value == null) { unbound_variable = true; } } } // if the generated fact has #authority or #ambient as first element and we're n ot in a privileged rule // do not generate it bool isRestrictedSymbol = false; ID first = predicate.Ids.FirstOrDefault(); if (first != null && first is ID.Symbol) { if (restrictedSymbols.Contains(((ID.Symbol)first).Value)) { isRestrictedSymbol = true; } } if (!unbound_variable && !isRestrictedSymbol) { newFacts.Add(new Fact(predicate)); } } }