public Conjunction<PatternAdmin> getPattern() { return Patterns.conjunction( getAtoms().stream() .map(Atomic::getCombinedPattern) .flatMap(p -> p.admin().varPatterns().stream()) .collect(Collectors.toSet()) ); }
public Pattern pattern(Relationship concept) { VarPattern relationPattern = Graql.var(); Set<Pattern> idPatterns = new HashSet<>(); for (Map.Entry<Role, Set<Thing>> entry : concept.rolePlayersMap().entrySet()) { for (Thing var : entry.getValue()) { Var rolePlayer = Graql.var(); relationPattern = relationPattern.rel(Graql.label(entry.getKey().label()), rolePlayer); idPatterns.add(rolePlayer.asUserDefined().id(var.id())); } } relationPattern = relationPattern.isa(Graql.label(concept.type().label())); Pattern pattern = relationPattern; for (Pattern idPattern : idPatterns) { pattern = pattern.and(idPattern); } return pattern; } }
/** * @param atoms of interest * @param subs extra substitutions in the form of id predicates * @return conjunctive pattern composed of atoms + their constraints + subs */ private static Conjunction<PatternAdmin> atomsToPattern(List<Atom> atoms, Set<IdPredicate> subs){ return Patterns.conjunction( Stream.concat( atoms.stream().flatMap(at -> Stream.concat(Stream.of(at), at.getNonSelectableConstraints())), subs.stream() ) .map(Atomic::getCombinedPattern) .flatMap(p -> p.admin().varPatterns().stream()) .collect(Collectors.toSet()) ); }
/** * @return var properties this atom (its pattern) contains */ public Stream<VarProperty> getVarProperties(){ return getCombinedPattern().admin().varPatterns().stream().flatMap(vp -> vp.getProperties(getVarPropertyClass())); }
/** * @param graph graph used to ensure the rule is a valid Horn clause * @param rule the rule to be validated * @return Error messages if the rule is not a valid Horn clause (in implication form, conjunction in the body, single-atom conjunction in the head) */ static Set<String> validateRuleIsValidHornClause(GraknTx graph, Rule rule){ Set<String> errors = new HashSet<>(); if (rule.when().admin().isDisjunction()){ errors.add(ErrorMessage.VALIDATION_RULE_DISJUNCTION_IN_BODY.getMessage(rule.label())); } if (errors.isEmpty()){ errors.addAll(validateRuleHead(graph, rule)); } return errors; }
private static ReasonerQuery combinedRuleQuery(GraknTx graph, Rule rule){ ReasonerQuery bodyQuery = rule.when().admin().getDisjunctiveNormalForm().getPatterns().iterator().next().toReasonerQuery(graph); ReasonerQuery headQuery = rule.then().admin().getDisjunctiveNormalForm().getPatterns().iterator().next().toReasonerQuery(graph); return headQuery.conjunction(bodyQuery); }
/** * @param graph graph used to ensure the rule head is valid * @param rule the rule to be validated * @return Error messages if the rule head is invalid - is not a single-atom conjunction, doesn't contain illegal atomics and is ontologically valid */ private static Set<String> validateRuleHead(GraknTx graph, Rule rule) { Set<String> errors = new HashSet<>(); Set<Conjunction<VarPatternAdmin>> headPatterns = rule.then().admin().getDisjunctiveNormalForm().getPatterns(); if (headPatterns.size() != 1){ errors.add(ErrorMessage.VALIDATION_RULE_DISJUNCTION_IN_HEAD.getMessage(rule.label())); } else { ReasonerQuery bodyQuery = Iterables.getOnlyElement(rule.when().admin().getDisjunctiveNormalForm().getPatterns()).toReasonerQuery(graph); ReasonerQuery headQuery = Iterables.getOnlyElement(headPatterns).toReasonerQuery(graph); ReasonerQuery combinedQuery = headQuery.conjunction(bodyQuery); Set<Atomic> headAtoms = headQuery.getAtoms(); combinedQuery.getAtoms().stream() .filter(headAtoms::contains) .map(at -> at.validateAsRuleHead(rule)) .forEach(errors::addAll); Set<Atomic> selectableHeadAtoms = headAtoms.stream() .filter(Atomic::isAtom) .filter(Atomic::isSelectable) .collect(Collectors.toSet()); if (selectableHeadAtoms.size() > 1) { errors.add(ErrorMessage.VALIDATION_RULE_HEAD_NON_ATOMIC.getMessage(rule.label())); } } return errors; }
@Override public Rule putRule(Label label, Pattern when, Pattern then) { Rule rule = putSchemaConcept(label, Schema.BaseType.RULE, false, v -> factory().buildRule(v, getMetaRule(), when, then)); //NB: thenTypes() will be empty as type edges added on commit //NB: this will cache also non-committed rules if (rule.then() != null){ rule.then().admin().varPatterns().stream() .flatMap(v -> v.getTypeLabels().stream()) .map(vl -> this.admin().<SchemaConcept>getSchemaConcept(vl)) .filter(Objects::nonNull) .filter(Concept::isType) .forEach(type -> ruleCache.updateRules(type, rule)); } return rule; }
Set<String> errors = new HashSet<>(); pattern.admin().varPatterns().stream() .flatMap(v -> v.innerVarPatterns().stream()) .flatMap(v -> v.getTypeLabels().stream()).forEach(typeLabel -> {