/******************************************************************************* * 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.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import br.usp.poli.takiyama.common.Constraint; /** * A parameterized random variable is either a logical atom or a term. * That is, it is of the form p(t1,...,tn), where each ti is a logical variable * or a constant and p is a functor. Each functor has a set of values called * the range of the functor [Kisynski, 2010]. The parameterized random variable * is said to be parameterized by the logical variables that appear in it. * [Poole, 2010] * * @author Felipe Takiyama * */ public final class StdPrv implements Prv { /* * Parameters are put in a list because they need to be ordered in a * predictable way. */ private final List<Term> parameters; private final String functor; private final List<RangeElement> range; /* ************************************************************************ * Constructors * ************************************************************************/ private StdPrv(String f, int pSize, int rSize) { parameters = new ArrayList<Term>(pSize); range = new ArrayList<RangeElement>(rSize); functor = f; } /** * Creates an empty Standard Parameterized Random Variable. */ private StdPrv() { this("", 0, 0); } /** * Creates a Standard Parameterized Random Variable with one {@link Term}. * * @param f The name of this PRV * @param r The range of this PRV * @param t The parameter of this PRV */ private StdPrv(String f, List<RangeElement> r, Term t) { this(f, 1, r.size()); for (RangeElement e : r) { range.add(e); } parameters.add(t); } /** * Creates a Standard Parameterized Random Variable with two {@link Term}s. * * @param f The name of this PRV * @param r The range of this PRV * @param t1 The first parameter of this PRV * @param t2 The second parameter of this PRV */ private StdPrv(String f, List<RangeElement> r, Term t1, Term t2) { this(f, 2, r.size()); for (RangeElement e : r) { range.add(e); } parameters.add(t1); parameters.add(t2); } /** * Creates a Standard Parameterized Random Variable. * * @param f The name of this PRV * @param r The range of this PRV * @param t The parameters of this PRV */ private StdPrv(String f, List<RangeElement> r, List<Term> t) { this(f, t.size(), r.size()); for (RangeElement e : r) { range.add(e); } for (Term p : t) { parameters.add(p); } } /** * Creates a copy of the specified Prv. * * @param prv The StdPrv to copy. * @throws IllegalArgumentException if the specified PRV is not a * {@link StdPrv} */ private StdPrv(Prv prv) throws IllegalArgumentException { this(prv.name(), prv.range(), prv.terms()); if (!(prv instanceof StdPrv)) { throw new IllegalArgumentException(); } } /* ************************************************************************ * Static factories * ************************************************************************/ /** * Returns an instance of standard parameterized random variable (StdPrv). * * @param f The name of the PRV * @param r The range of the PRV * @param t The parameters of the PRV * @return An instance of StdPrv. */ public static Prv getInstance(String f, List<RangeElement> r, List<Term> t) { return new StdPrv(f, r, t); } /** * Returns a copy of the given StdPrv. * * @param prv The StdPrv to copy. * @return A copy of the specified StdPrv. */ public static Prv getInstance(Prv prv) { return new StdPrv(prv); } /** * Returns an empty standard parameterized random variable. * It has a nameless functor, an empty set of parameters and no range. * * @return An empty StdPrv */ public static Prv getInstance() { return new StdPrv(); } /** * Returns a Boolean StdPrv. Its range is {false, true} * * @param f The name of the functor * @param vars Terms that parameterized the functor * @return a Boolean StdPrv with range {false, true} */ public static Prv getBooleanInstance(String f, Term ... vars) { List<RangeElement> range = new ArrayList<RangeElement>(2); range.add(Bool.valueOf(false)); range.add(Bool.valueOf(true)); List<Term> terms = Arrays.asList(vars); return new StdPrv(f, range, terms); } /* ************************************************************************ * Getters * ************************************************************************/ /** * Returns an empty set of {@link Constraint}. */ @Override public Set<Constraint> constraints() { return new HashSet<Constraint>(0); } @Override public String name() { return functor; } @Override public List<LogicalVariable> parameters() { List<LogicalVariable> param = new ArrayList<LogicalVariable>(parameters.size()); for (Term t : parameters) { if (t.isVariable()) { param.add((LogicalVariable) t); } } return param; } @Override public List<Term> terms() { return new ArrayList<Term>(parameters); } @Override public List<RangeElement> range() { return new ArrayList<RangeElement>(range); } /** * Returns an empty logical variable. */ @Override public LogicalVariable boundVariable() { return StdLogicalVariable.getInstance(); } @Override public int groundSetSize(Set<Constraint> constraints) { int size = 1; for (LogicalVariable v : parameters()) { size = size * v.individualsSatisfying(constraints).size(); } return size; } @Override public boolean contains(Term t) { return parameters.contains(t); } /** * Returns {@link BigDecimal#ONE}. */ @Override public BigDecimal getSumOutCorrection(RangeElement e) { return BigDecimal.ONE; } @Override public boolean isEquivalentTo(RandomVariableSet s) { /* * Not quite right. Should build each random variable set */ return s.prv().equals(this) && s.constraints().isEmpty(); } @Override public Prv getCanonicalForm() { // Not quite right. Should return a PRV with logical variables only return this; } /* ************************************************************************ * Setters * ************************************************************************/ @Override public Prv apply(Substitution s) { StdPrv substituted = new StdPrv(this); for (Iterator<LogicalVariable> it = s.getSubstitutedIterator(); it.hasNext(); ) { LogicalVariable toReplace = it.next(); Term replacement = s.getReplacement(toReplace); substituted.replace(toReplace, replacement); } return substituted; } /** * Replaces all occurrences of the term <code>toReplace</code> by the * <code>replacement</code> * in the list of parameters. If the term <code>toReplace</code> does not * exist, nothing is done. * * @param toReplace The term to replace * @param replacement The term that will replace the term * <code>toReplace</code>. */ private void replace(Term toReplace, Term replacement) { while (contains(toReplace)) { int substitutedIndex = parameters.indexOf(toReplace); parameters.set(substitutedIndex, replacement); } } @Override public Prv rename(String name) { return StdPrv.getInstance(name, range, parameters); } /* ************************************************************************ * hashCode, equals and toString * ************************************************************************/ @Override public String toString() { StringBuilder result = new StringBuilder(functor + " ( "); for (Term term : parameters) { result.append(term).append(" "); } result.append(")"); return result.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((functor == null) ? 0 : functor.hashCode()); result = prime * result + ((parameters == null) ? 0 : parameters.hashCode()); result = prime * result + ((range == null) ? 0 : range.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof StdPrv)) { return false; } StdPrv other = (StdPrv) obj; if (functor == null) { if (other.functor != null) { return false; } } else if (!functor.equals(other.functor)) { return false; } if (parameters == null) { if (other.parameters != null) { return false; } } else if (!parameters.equals(other.parameters)) { return false; } if (range == null) { if (other.range != null) { return false; } } else if (!range.equals(other.range)) { return false; } return true; } }