/******************************************************************************* * Copyright 2014 Felipe Takiyama * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package br.usp.poli.takiyama.prv; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.Stack; import br.usp.poli.takiyama.common.Constraint; import br.usp.poli.takiyama.common.EqualityConstraint; import br.usp.poli.takiyama.utils.Lists; import br.usp.poli.takiyama.utils.Sets; /** * Operations for {@link Prv}. * * @author Felipe Takiyama * */ public final class Prvs { public static Substitution mgu(Prv prv1, Prv prv2) throws IllegalArgumentException { if (!areUnifiable(prv1, prv2)) { throw new IllegalArgumentException(); } Stack<Constraint> buffer = pushEquations(prv1, prv2); List<Binding> mgu = new ArrayList<Binding>(); while (!buffer.isEmpty()) { EqualityConstraint equation = (EqualityConstraint) buffer.pop(); if (hasIdenticalTerms(equation)) { // do nothing } else if (equation.firstTerm().isVariable()) { Binding b = equation.toBinding(); buffer = apply(b, buffer); mgu.add(b); } else if (equation.secondTerm().isVariable()) { Binding b = equation.toInverseBinding(); buffer = apply(b, buffer); mgu.add(b); } else { throw new IllegalArgumentException(); } } Substitution result = Substitution.getInstance(mgu); return result; } private static boolean areUnifiable(Prv prv1, Prv prv2) { boolean sameFunctor = prv1.name().equals(prv2.name()); boolean sameNumberOfParam = (prv1.terms().size() == prv2.terms().size()); return sameFunctor && sameNumberOfParam; } private static Stack<Constraint> pushEquations(Prv prv1, Prv prv2) { Stack<Constraint> result = new Stack<Constraint>(); for (int i = 0; i < prv1.terms().size(); i++) { Term t1 = prv1.terms().get(i); Term t2 = prv2.terms().get(i); result.push(EqualityConstraint.getInstance(t1, t2)); } return result; } private static boolean hasIdenticalTerms(Constraint c) { return c.firstTerm().equals(c.secondTerm()); } private static Stack<Constraint> apply(Binding b, Stack<Constraint> buffer) { Substitution s = Substitution.getInstance(b); for (Constraint e : buffer) { e = (EqualityConstraint) e.apply(s); } return buffer; } /** * Returns <code>true</code> if the specified PRVs represent disjoint sets * of random variables. * @param prv1 * @param prv2 * @return */ public static boolean areDisjoint(Prv prv1, Prv prv2) { /* * This algorithm is similar to the one used in Shatter. * * rename all logical variables * get the MGU between these two variables * if MGU is empty OR error: * return true * else * if MGU is not consistent with constraints * return false * else * return true; */ // Renames all logical variables in PRVs boolean areDisjoint = false; List<LogicalVariable> allVariables = Lists.union( prv1.getCanonicalForm().parameters(), prv2.getCanonicalForm().parameters()); Prv renamed1 = prv1.apply(NameGenerator.rename(allVariables)); Prv renamed2 = prv2.apply(NameGenerator.rename(allVariables)); try { Substitution mgu = Prvs.mgu(renamed1.getCanonicalForm(), renamed2.getCanonicalForm()); Set<Constraint> constraints = Sets.union(renamed1.constraints(), renamed2.constraints()); if (mgu.isEmpty()) { // each PRV is a single random variable areDisjoint = !(renamed1.equals(renamed2)); } else { areDisjoint = !mgu.isConsistentWith(constraints); } } catch (IllegalArgumentException e) { areDisjoint = true; } return areDisjoint; } }