/** * */ package br.usp.poli.takiyama.acfove; import java.math.BigInteger; import br.usp.poli.takiyama.common.Marginal; import br.usp.poli.takiyama.common.Parfactor; import br.usp.poli.takiyama.common.StdMarginal.StdMarginalBuilder; import br.usp.poli.takiyama.prv.Binding; import br.usp.poli.takiyama.prv.Constant; import br.usp.poli.takiyama.prv.CountingFormula; import br.usp.poli.takiyama.prv.LogicalVariable; import br.usp.poli.takiyama.prv.Population; import br.usp.poli.takiyama.prv.Prv; import br.usp.poli.takiyama.prv.Substitution; /** * This operation represents the expansion of a counting formula * for all individuals from its bound variable satisfying its constraints. * <p> * Given a set of parfactors, it is always possible to fully expand a * counting formula from some parfactor. * </p> * <p> * After all the expansions, the {@link Shatter} macro operation is invoked to * guarantee that all parameterized random variables represent equal or * disjoint sets of random variables. * </p> * * @author Felipe Takiyama */ public final class FullExpand implements MacroOperation { // The marginal in which the parfactor to be expanded is contained private Marginal marginal; // The parfactor to be fully expanded private final Parfactor expandableParfactor; // The counting formula that will be expanded private final Prv expandableVariable; public FullExpand(Marginal marginal, Parfactor expandable, Prv countingFormula) { this.marginal = marginal; this.expandableParfactor = expandable; this.expandableVariable = countingFormula; } @Override public Marginal run() { // Fully expands the parfactor Parfactor expanded = fullExpand(); // Replaces the expanded parfactor in the marginal StdMarginalBuilder resultBuilder = new StdMarginalBuilder(); resultBuilder.add(marginal).replace(expandableParfactor, expanded); // Shatters the new marginal and returns the result Marginal result = new Shatter(resultBuilder.build()).run(); return result; } /** * Returns the result of fully expanding the expandable parfactor on * individuals from expandable variable. */ private Parfactor fullExpand() { Parfactor toExpand = expandableParfactor; Prv expandable = expandableVariable; // Keeps a reference for the counting formula being expanded int prvIndex = toExpand.factor().variables().indexOf(expandable); // Throws exception if expandable doesn't exist in the parfactor if (prvIndex == -1) { throw new IllegalStateException(); } // Get individuals from bound logical variables satisfying constraints Population population = getBoundedIndividuals(); for (Constant individual : population) { expandable = toExpand.factor().variables().get(prvIndex); LogicalVariable bound = expandable.boundVariable(); Binding b = Binding.getInstance(bound, individual); Substitution s = Substitution.getInstance(b); if (toExpand.isExpandable(expandable, s)) { toExpand = toExpand.expand(expandable, individual); } } return toExpand; } /* * Returns the number of individuals from the bounded logical variable * satisfying counting formula's constraints */ private Population getBoundedIndividuals() { return expandableVariable.boundVariable() .individualsSatisfying(expandableVariable.constraints()); } /** * The cost of full expand is the size of the factor it creates, which is * given by the following expression: * <p> * <sup>|F|</sup>⁄<sub>|range(γ)|</sub> * x |range(f)|<sup>|D(A):CA|</sup> * </p> * <p> * where * </p> * <li> ⟨ C, V, F ⟩ is the parfactor being expanded * <li> γ = #<sub>A:C<sub>A</sub></sub>[f(...,A,...)] is the counting * formula being expanded */ @Override public int cost() { int cost = ((int) Double.POSITIVE_INFINITY); if (isPossible()) { // Factor's size int factor = expandableParfactor.factor().size(); // Counting formula range size int countingFormula = expandableVariable.range().size(); // Counting formula associated PRV range size int prv = ((CountingFormula) expandableVariable).prvRangeSize(); // Number of individuals from the bounded logical variable satisfying // counting formula's constraints int domain = getBoundedIndividuals().size(); // Finally, the result //int resultSize = factor / countingFormula * ((int) Math.pow(prv, domain)); //cost = resultSize; /* * Here we have a potential overflow problem. * I calculate the cost and, if it is greater than Double.Infinity, * set the cost as infinity. */ BigInteger resSize = BigInteger.valueOf(factor / countingFormula).multiply(BigInteger.valueOf(prv).pow(domain)); if (resSize.compareTo(BigInteger.valueOf(((int) Double.POSITIVE_INFINITY) - 1)) == -1) { cost = resSize.intValue(); } else { cost = ((int) Double.POSITIVE_INFINITY) - 1; } } return cost; } private boolean isPossible() { boolean isPossible = false; Population population = getBoundedIndividuals(); if (population.size() != 0) { Constant someone = population.individualAt(0); LogicalVariable bound = expandableVariable.boundVariable(); Binding b = Binding.getInstance(bound, someone); Substitution s = Substitution.getInstance(b); isPossible = expandableParfactor.isExpandable(expandableVariable, s); } return isPossible; } /** * Returns zero. */ @Override public int numberOfRandomVariablesEliminated() { return 0; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("FULL-EXPAND").append("\n") .append(expandableParfactor).append("\non ") .append(expandableVariable); return builder.toString(); } }