/*******************************************************************************
* Copyright (c) 2013 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.util.triangulation;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.recommenders.jayes.util.Graph;
/**
* Graph elimination based on greedy minimum fill-in heuristic. Tie-breaking is done by using weights on the nodes. On
* tie, the node is chosen that will result in the cluster with a minimal sum of node weights
*/
public class GraphElimination implements Iterable<List<Integer>> {
private final Graph graph;
private final double[] nodeWeights;
private final IEliminationHeuristic heuristic;
public GraphElimination(Graph graph, double[] nodeWeights, IEliminationHeuristic heuristic) {
this.nodeWeights = nodeWeights;
this.graph = graph;
this.heuristic = heuristic;
}
private List<Integer> getNodeList() {
final List<Integer> moralNodes = new LinkedList<Integer>();
for (int i = 0; i < graph.numberOfVertices(); i++) {
moralNodes.add(i);
}
return moralNodes;
}
@Override
public Iterator<List<Integer>> iterator() {
return new Iterator<List<Integer>>() {
private List<Integer> nodes = getNodeList();
private QuotientGraph graph = new QuotientGraph(GraphElimination.this.graph);
@Override
public boolean hasNext() {
return !nodes.isEmpty();
}
@Override
public List<Integer> next() {
int next = nextTriangulationNode();
nodes.remove(Integer.valueOf(next));
List<Integer> result = createClique(next);
graph.eliminate(next);
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
private int nextTriangulationNode() {
int minCost = Integer.MAX_VALUE;
Double nextClusterWeight = Double.MAX_VALUE;
int returnNode = 0;
for (final int node : nodes) {
final int predictedCost = heuristic.getHeuristicValue(graph, node);
if (predictedCost <= minCost) {
final double clusterWeight = computeClusterWeight(node);
if (predictedCost < minCost || clusterWeight < nextClusterWeight) {
returnNode = node;
minCost = predictedCost;
nextClusterWeight = clusterWeight;
}
}
}
return returnNode;
}
private double computeClusterWeight(final int node) {
double clSize = nodeWeights[node];
for (final int neighbor : graph.getNeighbors(node)) {
clSize += nodeWeights[neighbor];
}
return clSize;
}
private List<Integer> createClique(final int centerNode) {
final List<Integer> clique = new ArrayList<Integer>();
clique.add(centerNode);
for (final int neighbor : graph.getNeighbors(centerNode)) {
clique.add(neighbor);
}
return clique;
}
};
}
}