/******************************************************************************* * Copyright (C) 2008-2012 Dominik Jain. * * This file is part of ProbCog. * * ProbCog is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ProbCog is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ProbCog. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package probcog.bayesnets.inference; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Random; import probcog.bayesnets.core.BeliefNetworkEx; import probcog.bayesnets.core.Discretized; import edu.ksu.cis.bnj.ver3.core.BeliefNode; import edu.ksu.cis.bnj.ver3.core.Domain; /** * An instance of class <code>WeightedSample</code> represents a weighted * sample. It contains the mapping from node to the corresponding value and * the value of the sample. * * @see BeliefNetworkEx#getWeightedSample(String[][], Random) */ public class WeightedSample implements Cloneable{ BeliefNetworkEx bn; /** * The mapping from intern numbering to value as index into the domain * of the node. */ public int[] nodeDomainIndices; /** * The mapping from intern numbering to the node index of the outer * class {@link BeliefNetworkEx}. */ public int[] nodeIndices; /** * The weight of the sample. */ public double weight; /** * the number of trials/restarts/backtrackings was required to obtain the sample; */ public int trials; /** * the number of operations used to obtain the sample */ public int operations; /** * Constructs a weighted sample from given node value mapping and * weight. * * @param nodeDomainIndices * the mapping from intern numbering to value as index into * the domain of the node. * @param weight * the weight of the sample. * @param nodeIndices * the mapping from intern numbering to the node index of the * outer class. * (may be null, in which case the identity mapping is assumed) * @param trials * the number of steps that was required to obtain this sample */ public WeightedSample(BeliefNetworkEx bn, int[] nodeDomainIndices, double weight, int[] nodeIndices, int trials) { this.bn = bn; if (nodeIndices == null) { int numNodes = nodeDomainIndices.length; nodeIndices = new int[numNodes]; for (int i = 0; i < numNodes; i++) { nodeIndices[i] = i; } } this.nodeIndices = nodeIndices; this.nodeDomainIndices = nodeDomainIndices; assert nodeIndices.length == nodeDomainIndices.length; this.weight = weight; this.trials = trials; } /** * constructs an empty sample with initial weight 1.0 and 0 trials, with an identity node mapping * @param bn the Bayesian network this sample is for */ public WeightedSample(BeliefNetworkEx bn) { this(bn, new int[bn.bn.getNodes().length], 1.0, null, 0); } public WeightedSample(BeliefNetworkEx bn, int[] domainIndices) { this(bn, domainIndices, 1.0, null, 0); } /** * Extract a sub sample of this sample for the given nodes. The weight * of the sample has to be normalised afterwards and is only meaningful * with the same node base! * * @param queryNodes * the nodes to be extracted. * @return the sub sample for the given nodes. */ public WeightedSample subSample(int[] queryNodes) { //BeliefNetworkEx.logger.debug(Arrays.toString(nodeDomainIndices)); int[] resultIndices = new int[queryNodes.length]; for (int i = 0; i < queryNodes.length; i++) { resultIndices[i] = nodeDomainIndices[queryNodes[i]]; } return new WeightedSample(bn, resultIndices, weight, queryNodes, 1); } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return Arrays.hashCode(nodeDomainIndices); } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof WeightedSample)) return false; return Arrays.equals(nodeDomainIndices, (((WeightedSample) obj).nodeDomainIndices)); } /** * Get the assignment from node names to the values. Sometimes we don't * want to use the internal numbering outside this class. * * @return the assignments of this sample. */ public Map<String, String> getAssignmentMap() { Map<String, String> result = new HashMap<String, String>(); BeliefNode[] nodes = bn.bn.getNodes(); for (int i = 0; i < nodeIndices.length; i++) { try { result.put(nodes[nodeIndices[i]].getName(), nodes[nodeIndices[i]].getDomain().getName( nodeDomainIndices[i])); } catch (RuntimeException e) { e.printStackTrace(); throw e; } } return result; } /** * Get the assignment from node names to values but use an example value * for {@link Discretized} domains. * * @return the assignments of this sample probably with example values. */ public Map<String, String> getUndiscretizedAssignmentMap() { Map<String, String> result = new HashMap<String, String>(); BeliefNode[] nodes = bn.bn.getNodes(); for (int i = 0; i < nodeIndices.length; i++) { try { Domain nodeDomain = nodes[nodeIndices[i]].getDomain(); String value = nodeDomain.getName(nodeDomainIndices[i]); if (nodeDomain instanceof Discretized) { value = String.valueOf(((Discretized) nodeDomain) .getExampleValue(nodeDomainIndices[i])); } result.put(nodes[nodeIndices[i]].getName(), value); } catch (RuntimeException e) { e.printStackTrace(); throw e; } } return result; } public synchronized WeightedSample clone() throws CloneNotSupportedException { WeightedSample clone = (WeightedSample)super.clone(); clone.nodeDomainIndices = this.nodeDomainIndices.clone(); return clone; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return "WeightedSample(" + getAssignmentMap() + ", " + weight + ")"; } /** * Get only a shorter String containing only the the domain indices * instead of the full assignment map. * * @return a short string representation. */ public String toShortString() { return "WeightedSample(" + Arrays.toString(nodeDomainIndices) + ", " + weight + ")"; } /** * Check if all query assignments are this sample's assignments. * * @param queries * the assignments to be tested. * @return true if all the assignments are correct, * false otherwise */ public boolean checkAssignment(String[][] queries) { int[] indices = bn.getNodeDomainIndicesFromStrings(queries); for (int nodeIndex : nodeIndices) { if (indices[nodeIndex] >= 0 && indices[nodeIndex] != nodeDomainIndices[nodeIndex]) return false; } return true; } public String getCPDLookupString(BeliefNode node) { BeliefNode[] domain_product = node.getCPF().getDomainProduct(); StringBuffer cond = new StringBuffer(); for(int i = 0; i < domain_product.length; i++) { if(i > 0) cond.append(", "); cond.append(domain_product[i].getName()).append(" = "); int domIdx = nodeDomainIndices[this.bn.getNodeIndex(domain_product[i])]; if(domIdx >= 0) cond.append(domain_product[i].getDomain().getName(domIdx)); else cond.append(Integer.toString(domIdx)); } return cond.toString(); } }