/** * Copyright (c) 2011 Michael Kutschke. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Michael Kutschke - initial API and implementation. */ package org.eclipse.recommenders.jayes.inference.jtree; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.ListIterator; import org.eclipse.recommenders.jayes.BayesNet; import org.eclipse.recommenders.jayes.BayesNode; import org.eclipse.recommenders.jayes.util.Graph; import org.eclipse.recommenders.jayes.util.OrderIgnoringPair; import org.eclipse.recommenders.jayes.util.Pair; import org.eclipse.recommenders.jayes.util.triangulation.GraphElimination; import org.eclipse.recommenders.jayes.util.triangulation.IEliminationHeuristic; public class JunctionTreeBuilder { private final IEliminationHeuristic heuristic; public static JunctionTreeBuilder forHeuristic(IEliminationHeuristic heuristic) { return new JunctionTreeBuilder(heuristic); } protected JunctionTreeBuilder(IEliminationHeuristic heuristic) { this.heuristic = heuristic; } public JunctionTree buildJunctionTree(BayesNet net) { JunctionTree junctionTree = new JunctionTree(); junctionTree.setClusters(triangulateGraphAndFindCliques(buildMoralGraph(net), weightNodesByOutcomes(net), heuristic)); junctionTree.setSepSets(computeSepsets(junctionTree, net)); return junctionTree; } private Graph buildMoralGraph(BayesNet net) { Graph moral = new Graph(net.getNodes().size()); for (final BayesNode node : net.getNodes()) { addMoralEdges(moral, node); } return moral; } private void addMoralEdges(Graph moral, final BayesNode node) { final ListIterator<BayesNode> it = node.getParents().listIterator(); while (it.hasNext()) { final BayesNode parent = it.next(); final ListIterator<BayesNode> remainingParentsIt = node.getParents().listIterator(it.nextIndex()); while (remainingParentsIt.hasNext()) { // connect parents final BayesNode otherParent = remainingParentsIt.next(); moral.addEdge(parent.getId(), otherParent.getId()); } moral.addEdge(node.getId(), parent.getId()); } } private List<List<Integer>> triangulateGraphAndFindCliques(Graph graph, double[] weights, IEliminationHeuristic eliminationHeuristic) { GraphElimination triangulate = new GraphElimination(graph, weights, eliminationHeuristic); final List<List<Integer>> cliques = new ArrayList<List<Integer>>(); for (List<Integer> nextClique : triangulate) { if (!containsSuperset(cliques, nextClique)) { cliques.add(nextClique); } } return cliques; } private double[] weightNodesByOutcomes(BayesNet net) { double[] weights = new double[net.getNodes().size()]; for (BayesNode node : net.getNodes()) { weights[node.getId()] = Math.log(node.getOutcomeCount()); // using these weights is the same as minimizing the resulting cluster factor size // which is given by the product of the variable outcome counts. } return weights; } private boolean containsSuperset(final Collection<? extends Collection<Integer>> sets, final Collection<Integer> set) { boolean isSubsetOfOther = false; for (final Collection<Integer> superset : sets) { if (superset.containsAll(set)) { isSubsetOfOther = true; break; } } return isSubsetOfOther; } private List<Pair<OrderIgnoringPair<Integer>, List<Integer>>> computeSepsets(JunctionTree junctionTree, BayesNet net) { return new SepsetComputer().computeSepsets(junctionTree, net); } }