public static boolean isomorphic(DefaultRule a, DefaultRule b) { a = preprocess(a); b = preprocess(b); Matching m = new Matching(); Clause ca = new Clause(Sugar.iterable(a.antecedent().literals(), a.consequent().literals())); Clause cb = new Clause(Sugar.iterable(b.antecedent().literals(), b.consequent().literals())); return ca.variables().size() == cb.variables().size() && ca.literals().size() == cb.literals().size() && m.isomorphism(ca, cb); }
public static void main(String[] args) { DefaultRule a = new DefaultRule(Clause.parse("a(X)"), Clause.parse("a(Y)")); DefaultRule b = new DefaultRule(Clause.parse("a(A)"), Clause.parse("a(B)")); DefaultRule c = new DefaultRule(Clause.parse("a(A)"), Clause.parse("a(A)")); DefaultRule d = new DefaultRule(Clause.parse("a(A,a)"), Clause.parse("b(B,b)")); DefaultRule e = new DefaultRule(Clause.parse("a(A,b)"), Clause.parse("b(B,a)")); DefaultRule f = new DefaultRule(Clause.parse("a(A,c)"), Clause.parse("b(B,d)")); for (DefaultRule r : selectNonisomorphicDefaultRules(Sugar.list(a, b, c, d))) { System.out.println(r); } System.out.println( partitionInterchangeableConstants(Sugar.list(a, b, c, d, e, f), Sugar.<Clause>set())); }
public static Set<DefaultRule> selectNonisomorphicDefaultRules( Iterable<DefaultRule> defaultRules) { List<Clause> candidates = new ArrayList<Clause>(); for (DefaultRule rule : defaultRules) { DefaultRule preprocessed = preprocess(rule); candidates.add( new Clause( Sugar.<Literal>iterable( preprocessed.antecedent().literals(), preprocessed.consequent().literals()))); } Matching m = new Matching(); Set<DefaultRule> retVal = new HashSet<DefaultRule>(); for (Clause c : m.nonisomorphic(candidates)) { List<Literal> head = new ArrayList<Literal>(); List<Literal> body = new ArrayList<Literal>(); for (Literal l : c.literals()) { Literal newLiteral = new Literal( l.predicate().substring(l.predicate().indexOf(":") + 1), l.isNegated(), l.arity()); for (int i = 0; i < l.arity(); i++) { newLiteral.set(l.get(i), i); } if (l.predicate().startsWith("antecedent:") || l.predicate().startsWith(SymmetricPredicates.PREFIX + "antecedent:")) { body.add(newLiteral); } else { head.add(newLiteral); } } retVal.add(new DefaultRule(new Clause(body), new Clause(head))); } return retVal; }
private static MultiMap<Variable, Variable> surelyDifferent(DefaultRule rule) { Clause body = rule.antecedent(); Clause head = rule.consequent(); final MultiMap<Variable, Variable> different = new MultiMap<Variable, Variable>(); for (Literal literal : Sugar.union( body.getLiteralsByPredicate(SpecialBinaryPredicates.NEQ), body.getLiteralsByPredicate(SpecialBinaryPredicates.GT), body.getLiteralsByPredicate(SpecialBinaryPredicates.LT), body.getLiteralsByPredicate(SpecialVarargPredicates.ALLDIFF), head.getLiteralsByPredicate(SpecialBinaryPredicates.NEQ), head.getLiteralsByPredicate(SpecialBinaryPredicates.GT), head.getLiteralsByPredicate(SpecialBinaryPredicates.LT), head.getLiteralsByPredicate(SpecialVarargPredicates.ALLDIFF))) { for (Term a : literal.terms()) { if (a instanceof Variable) { Variable v1 = (Variable) a; for (Term b : literal.terms()) { if (b instanceof Variable) { Variable v2 = (Variable) b; if (v1 != v2) { different.put(v1, v2); } } } } } } return different; }
public static List<Set<Constant>> partitionInterchangeableConstants( Collection<DefaultRule> rules, Collection<Clause> hardRules) { List<Set<Constant>> retVal = new ArrayList<Set<Constant>>(); Collection<DefaultRule> dummyRules = Sugar.<Clause, DefaultRule>funcall( hardRules, new Sugar.Fun<Clause, DefaultRule>() { @Override public DefaultRule apply(Clause clause) { return new DefaultRule(new Clause(Sugar.<Literal>list()), clause); } }); for (List<Set<Constant>> list : partitionExchangeable_impl(Sugar.union(rules, dummyRules)).values()) { retVal.addAll(list); } return retVal; }
private static Set<Term> constants(Iterable<DefaultRule> rules) { Set<Term> retVal = new HashSet<Term>(); for (DefaultRule rule : rules) { for (Term t : Sugar.<Term>iterable(rule.antecedent().terms(), rule.consequent().terms())) { if (t instanceof Constant) { retVal.add(t); } } } return retVal; }
private static MultiList<Object, Set<Constant>> partitionExchangeable_impl( Iterable<DefaultRule> rules) { MultiMap<Term, Term> partitioning = new MultiMap<Term, Term>(); List<Term> constants = Sugar.arrayListFromCollections(constants(rules)); Set<Term> closed = new HashSet<Term>(); // checking interchangeability pairwise for (int i = 0; i < constants.size(); i++) { if (!closed.contains(constants.get(i))) { partitioning.put(constants.get(i), constants.get(i)); for (int j = i + 1; j < constants.size(); j++) { if (areExchangeable(constants.get(i), constants.get(j), rules)) { partitioning.put(constants.get(i), constants.get(j)); closed.add(constants.get(j)); } } } } Map<Constant, Constant> map = new HashMap<Constant, Constant>(); for (Map.Entry<Term, Set<Term>> entry : partitioning.entrySet()) { Constant lexmin = null; for (Term t : entry.getValue()) { if (t instanceof Constant) { if (lexmin == null || t.toString().compareTo(lexmin.toString()) < 0) { lexmin = (Constant) t; } } } for (Term t : entry.getValue()) { if (t instanceof Constant) { map.put((Constant) t, lexmin); } } } MultiMap<Pair<Object, Constant>, Constant> mm = new MultiMap<Pair<Object, Constant>, Constant>(); for (Map.Entry<Constant, Constant> entry : map.entrySet()) { mm.put( new Pair<Object, Constant>( entry.getValue().type() == null ? Sugar.NIL : entry.getValue().type(), entry.getValue()), entry.getKey()); } MultiList<Object, Set<Constant>> retVal = new MultiList<Object, Set<Constant>>(); for (Map.Entry<Pair<Object, Constant>, Set<Constant>> entry : mm.entrySet()) { retVal.put(entry.getKey().r, entry.getValue()); } return retVal; }
public static Triple<Set<DefaultRule>, Set<Clause>, List<Set<Constant>>> preprocessConstants( Collection<DefaultRule> rules, Collection<Clause> hardRules, List<Set<Constant>> interchangeable) { final Map<Term, Term> typedConstants = new HashMap<Term, Term>(); List<Set<Constant>> retInterchangeable = new ArrayList<Set<Constant>>(); for (Set<Constant> set : interchangeable) { String type = min(set).name(); Set<Constant> newSet = new HashSet<Constant>(); for (Constant c : set) { Constant typedConstant = Constant.construct(c.name(), type); typedConstants.put(c, typedConstant); newSet.add(typedConstant); } retInterchangeable.add(newSet); } Collection<DefaultRule> retDefaultRules = Sugar.funcall( rules, new Sugar.Fun<DefaultRule, DefaultRule>() { @Override public DefaultRule apply(DefaultRule defaultRule) { return DefaultTransformationUtils.substitute(defaultRule, typedConstants); } }); Collection<Clause> retHardRules = Sugar.funcall( hardRules, new Sugar.Fun<Clause, Clause>() { @Override public Clause apply(Clause hardRule) { return LogicUtils.substitute(hardRule, typedConstants); } }); return new Triple<Set<DefaultRule>, Set<Clause>, List<Set<Constant>>>( Sugar.setFromCollections(retDefaultRules), Sugar.setFromCollections(retHardRules), Sugar.listFromCollections(retInterchangeable)); }
public static Clause clauseFromDefault(DefaultRule rule) { return new Clause( Sugar.iterable( Utils.flipSigns(rule.antecedent().literals()), rule.consequent().literals())); }
public static MultiMap<DefaultRule, DefaultRule> representativeBodySpecializations( DefaultRule rule, List<Set<Constant>> interchangeableConstants) { Clause body = rule.antecedent(); Clause head = rule.consequent(); final MultiMap<Variable, Variable> different = surelyDifferent(rule); final List<Variable> variables = Sugar.<Variable>listFromCollections(body.variables()); List<Integer> indices = VectorUtils.toList(VectorUtils.sequence(0, variables.size() - 1)); List<Tuple<Integer>> unifications = Combinatorics.<Integer>cartesianPower( indices, indices.size(), new Sugar.Fun<Tuple<Integer>, Boolean>() { @Override public Boolean apply(Tuple<Integer> integerTuple) { for (int i = 0; i < integerTuple.size(); i++) { if (integerTuple.get(i) > i || !integerTuple.get(i).equals(integerTuple.get(integerTuple.get(i))) || different .get(variables.get(integerTuple.get(i))) .contains(variables.get(i)) || !sameType(variables.get(integerTuple.get(i)), variables.get(i))) { return Boolean.FALSE; } } return Boolean.TRUE; } }); Set<DefaultRule> nonIsomorphicUnifications = new HashSet<DefaultRule>(); for (Tuple<Integer> unification : unifications) { Map<Term, Term> substitution = new HashMap<Term, Term>(); for (int i = 0; i < unification.size(); i++) { substitution.put(variables.get(i), variables.get(unification.get(i))); } Clause newBody = LogicUtils.substitute(rule.antecedent(), substitution); Clause newHead = LogicUtils.substitute(rule.consequent(), substitution); nonIsomorphicUnifications.add( new DefaultRule( newBody.variables().size() > 1 ? new Clause(Sugar.union(newBody.literals(), allDiffLiteral(newBody))) : newBody, newHead)); } nonIsomorphicUnifications = DefaultTransformationUtils.selectNonisomorphicDefaultRules(nonIsomorphicUnifications); MultiMap<DefaultRule, DefaultRule> retVal = new MultiMap<DefaultRule, DefaultRule>(); // this needs to be improved... e.g. using typing information... MultiList<Integer, Constant> consts = new MultiList<Integer, Constant>(); int index = 0; for (Set<Constant> interch : interchangeableConstants) { consts.putAll(index++, interch); } for (DefaultRule unifiedRule : nonIsomorphicUnifications) { List<Variable> unifsVariables = Sugar.listFromCollections(unifiedRule.variables()); if (unifsVariables.isEmpty()) { retVal.put(unifiedRule, unifiedRule); } else { Set<DefaultRule> substituted = new HashSet<DefaultRule>(); middleLoop: for (Tuple<Integer> tuple : Combinatorics.cartesianPower( new NaturalNumbersList(0, interchangeableConstants.size()), unifsVariables.size())) { Counters<Integer> used = new Counters<Integer>(); Map<Term, Term> substitution = new HashMap<Term, Term>(); for (int i = 0; i < unifsVariables.size(); i++) { int j = used.incrementPost(tuple.get(i)); if (j >= consts.get(tuple.get(i)).size()) { continue middleLoop; } else { if (unifsVariables.get(i).type() == null) { substitution.put( unifsVariables.get(i), Variable.construct( unifsVariables.get(i).name(), consts.get(tuple.get(i)).get(j).type())); } else { if (unifsVariables.get(i).type().equals(consts.get(tuple.get(i)).get(j).type())) { substitution.put( unifsVariables.get(i), Variable.construct( unifsVariables.get(i).name(), consts.get(tuple.get(i)).get(j).type())); } else { continue middleLoop; } } } } substituted.add(DefaultTransformationUtils.substitute(unifiedRule, substitution)); } retVal.putAll( unifiedRule, DefaultTransformationUtils.selectNonisomorphicDefaultRules(substituted)); } } return retVal; }