package org.societies.context.user.refinement.impl.bayesianLibrary.inference.solving;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.solving.exceptions.BayesletDAGIncompatibilityException;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.solving.utils.CliqueBLOperations;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.Clique;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.DAG;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.Node;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.ProbabilityDistribution;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.Separator;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.UndirectedEdge;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.bayeslets.Bayeslet;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.bayeslets.BayesletInfo;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.bayeslets.CliqueBL;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.bayeslets.InterfaceNodeRecord;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.bayeslets.NodeBL;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl.bayeslets.ProbabilityDistributionBL;
import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.interfaces.HasProbabilityTable;
import org.societies.context.user.refinement.impl.tools.ArrayListConverter;
public class BayesletJTree extends JunctionTree {
static boolean screenEnabled = false;
public BayesletJTree(DAG dag) {
super(dag);
}
// ///////////////////////////////////////////////////////////
// ////////////////////Added by Pablo/////////////////////////
// ///////////////////////////////////////////////////////////
/**
* @author gall_pa Empty constructor, necessary to create the combined JT in
* the third approach.
*/
public BayesletJTree() {
super();
}
/**
* @author gall_pa This method combines the parent cliques corresponding to
* nodes called sourceNodeName and targetNodeName. It is used in the
* third approach to construct the combined junction tree.
*
* @param sourceNodeName
*
* @param targetNodeName
* @throws BayesletDAGIncompatibilityException
*/
public void combineCliques(String sourceNodeName, String targetNodeName) throws BayesletDAGIncompatibilityException {
int index = 0;
NodeBL targetNode = CliqueBLOperations.searchNode(targetNodeName,
new ArrayList<HasProbabilityTable>(this.getNodes().values()));
Clique tempClique = targetNode.getParentClique();
if (!(tempClique instanceof CliqueBL))
throw new BayesletDAGIncompatibilityException();
CliqueBL targetClique = (CliqueBL) tempClique;
ArrayList<NodeBL> nodesTargetClique = new ArrayList<NodeBL>(Arrays
.asList((NodeBL[]) targetClique.getParticipants()));
NodeBL sourceNode = CliqueBLOperations.searchNode(sourceNodeName,
new ArrayList<HasProbabilityTable>(this.getNodes().values()));
Clique sourceClique = sourceNode.getParentClique();
// First step: combine both nodes.
ProbabilityDistribution pede = targetNode.getProbTable();
if (!(pede instanceof ProbabilityDistributionBL))
throw new BayesletDAGIncompatibilityException();
((ProbabilityDistributionBL) pede).combineProbabilityDistribution(
sourceNode, targetNode);
// Second step: transfer edges from sourceNode to targetNode
CliqueBLOperations.transferEdges(sourceNode, targetNode, this
.getEdges());
CliqueBLOperations.transferUndirectedEdges(sourceNode, targetNode, this
.getEdges());
// Updating name of target node.
targetNode.updateName(sourceNodeName);
/*
* Testing
* System.out.println("Probability tables combination result: \n");
* System.out.println(targetNode.getProbTable().toString());
*/
/*
* Third step: add all nodes contained in the parent clique from the
* source node (except the source node) to the parent clique from the
* target node. (The source node is not added because its probabilistic
* information and edges are already represented by the node resulting
* of the combination of the source node and the target node.
*/
index = 0;
ArrayList<NodeBL> nodesSourceClique = new ArrayList<NodeBL>(Arrays
.asList((NodeBL[]) sourceClique.getParticipants()));// CliqueBLOperations.arrayToArrayList(());
nodesSourceClique.remove(sourceNode);
// Updating parent clique of nodes that are going to be added to the
// target clique.
// Those whose parent clique was the source clique, will be now assigned
// the target clique as their parent clique.
while (index < nodesSourceClique.size()) {
NodeBL temp = (NodeBL) nodesSourceClique.get(index);
if (temp.getParentClique() == sourceClique)
temp.setParentClique(targetClique);
index++;
}
nodesTargetClique.addAll(nodesSourceClique);
targetClique.addNodes(nodesTargetClique);
/*
* Fourth step: Connecting all nodes inside the combined clique. This
* way we are ensuring the clique is complete: this means that every
* pair of distinct nodes are connected by an edge.
*/
for (int i = 0; i < nodesTargetClique.size(); i++) {
Node node1 = (Node) nodesTargetClique.get(i);
for (int j = i + 1; j < nodesTargetClique.size(); j++) {
Node node2 = (Node) nodesTargetClique.get(j);
UndirectedEdge u = new UndirectedEdge(node1, node2);
if (!getEdges().contains(u)) {
getEdges().add(u);
node1.addConnection(u);
node2.addConnection(u);
}
}
}
/*
* Fifth step: Transfer all separators that were previously connected to
* the source clique (the parent clique from the source node) to the
* target clique (namely the parent clique from the target node). The
* source node and the source clique are removed.
*/
getNodes().remove(sourceNode.getName());
// targetClique.addCombinedCliqueName("+"+sourceClique.getName());
updateCliques(sourceNode, targetNode, ArrayListConverter
.<CliqueBL, Clique> convertToSubclass(getCliquesArrayList()));
transferSeparators(sourceClique, targetClique);
getCliquesArrayList().remove(sourceClique);
}
/**
* This method modifies all cliques containing the source node, so they will
* contain the target node instead.
*
* @param sourceNode
* @param targetNode
* @param inputCliques
*/
public void updateCliques(NodeBL sourceNode, NodeBL targetNode,
ArrayList<CliqueBL> inputCliques) {
int indexCliques = 0;
int indexNodes = 0;
while (indexCliques < inputCliques.size()) {
indexNodes = 0;
CliqueBL tempClique = inputCliques.get(indexCliques);
NodeBL[] tempRepNodes = (NodeBL[]) tempClique.getParticipants();
while (indexNodes < tempRepNodes.length) {
if (tempRepNodes[indexNodes].getName().contains(
sourceNode.getName())) {
tempRepNodes[indexNodes] = targetNode;
tempClique.updateClique(tempRepNodes);
// updateSeparatorLabel(sourceNode,targetNode,tempRepNodes[])
}
indexNodes++;
}
indexCliques++;
}
}
/**
* This method transfer the separators from one clique to another. Every
* separator that was connected to the source clique will be redirected to
* the target clique.
*
* @author gall_pa
* @param sourceClique
* @param targetClique
*/
public void transferSeparators(Clique sourceClique, Clique targetClique) {
int indexSeparators = 0;
ArrayList<Separator> tempSep = this.getSeparatorsArrayList();
// It goes through all separators related to the source clique
while (indexSeparators < tempSep.size()) {
Separator temp = (Separator) tempSep.get(indexSeparators);
if (temp.getBorder1() == sourceClique) {
// Creates a new separator changing border 2
Separator newS = new Separator(targetClique, (Clique) temp
.getBorder2());
targetClique.addConnection(newS);
temp.getBorder2().removeConnection(temp);
temp.getBorder2().addConnection(newS);
// Updates the separators contained in the clique
getSeparatorsArrayList().remove(temp);
getSeparatorsArrayList().add(newS);
if (screenEnabled) {
System.out
.println("----------Separator CHANGE -----------------------------------------------------------");
System.out.println(temp.toString() + " changes to \n"
+ newS.toString());
System.out
.println("--------------------------------------------------------------------------------------");
}
} else if (temp.getBorder2() == sourceClique) {
// Creates a new separator changing border 1
Separator newS = new Separator((Clique) temp.getBorder1(),
targetClique);
targetClique.addConnection(newS);
temp.getBorder1().removeConnection(temp);
temp.getBorder1().addConnection(newS);
// Updates the separators contained in the clique
getSeparatorsArrayList().remove(temp);
getSeparatorsArrayList().add(newS);
if (screenEnabled) {
System.out
.println("----------Separator CHANGE -----------------------------------------------------------");
System.out.println(temp.toString() + "\n changes to \n"
+ newS.toString());
System.out
.println("--------------------------------------------------------------------------------------");
}
}
indexSeparators++;
}
}
/**
* This method adds all cliques and separators correponding to bayeslets
* contained in bayeslets[] to the common JT. It also adds their nodes and
* their edges. It is the first step when constructing the combined junction
* tree in the third approach.
*
* @param bayeslets
*/
public void addCliqNodEdSep(Bayeslet bayeslets[]) {
int indexBayeslets = 0;
BayesletJTree tempJT;
ArrayList<CliqueBL> tempCliques;
while (indexBayeslets < bayeslets.length) {
tempJT = bayeslets[indexBayeslets].getJunctionTree();
tempCliques = CliqueBLOperations.arrayToArrayList((CliqueBL[]) tempJT
.getCliques());
getCliquesArrayList().addAll((ArrayList) tempCliques.clone());
getNodes().putAll((HashMap<String,HasProbabilityTable>)tempJT.getNodes().clone());
getEdges().addAll((ArrayList) tempJT.getEdges().clone());
getSeparatorsArrayList().addAll(
(ArrayList) tempJT.getSeparatorsArrayList().clone());
indexBayeslets++;
}
}
/**
* This method combines those cliques that are defined as the parent cliques
* from those interface nodes whose connections have to be updated. It is
* the second step when constructing the combined junction tree in the third
* approach.
*
* @param bayeslets
* @throws BayesletDAGIncompatibilityException
*/
public void updateConnections(Bayeslet bayeslets[]) throws BayesletDAGIncompatibilityException {
int indexBayeslets = 0;
int indexInterfaceNodes = 0;
int indexConnectedBayeslets = 0;
ArrayList tempIncomingInterfaceNodes;
while (indexBayeslets < bayeslets.length) {
tempIncomingInterfaceNodes = bayeslets[indexBayeslets]
.getIncomingInterfaceNodes();
indexInterfaceNodes = 0;
while (indexInterfaceNodes < tempIncomingInterfaceNodes.size()) {
// Goes through all incoming interface nodes.
InterfaceNodeRecord tempINR = (InterfaceNodeRecord) tempIncomingInterfaceNodes
.get(indexInterfaceNodes);
if (tempINR.getToBeUpdatedNode()) {
ArrayList<BayesletInfo> tempConnectedBayeslets = tempINR
.getConnectedBayeslets();
indexConnectedBayeslets = 0;
while (indexConnectedBayeslets < tempConnectedBayeslets
.size()) {
// Goes through all bayeslets connected to interface
// node represented by .
BayesletInfo tempBI = ((BayesletInfo) tempConnectedBayeslets
.get(indexConnectedBayeslets));
String nodeName = tempBI.getNodeName();
// Combines the corresponding cliques
this.combineCliques(nodeName, tempINR.getName());
indexConnectedBayeslets++;
}
tempINR.setToBeUpdatedNode(false);
}
indexInterfaceNodes++;
}
indexInterfaceNodes = 0;
indexBayeslets++;
}
this.initialiseJTree();
this.propagate();
}
// ////////////////////////////////////////////////////
// ////////////////////NOT USED SO FAR/////////////////
// ////////////////////////////////////////////////////
/**
* This method dissolves the parent clique from the node called nodeName.
*
* @param nodeName
*/
/*
* public void dissolveCombinedClique(String nodeName,Bayeslet[]
* bayeslets,Bayeslet[] backUpBayeslets){
*
* ArrayList allDissolvedNodes=new ArrayList(); int indexCliquesNames=0; int
* indexNodeNames=0; ArrayList tempNodes= this.getNodes(); Node
* targetNode=CliqueOperations.searchNode(nodeName, tempNodes); Clique
* targetClique=targetNode.getParentClique();
*
* this.getCliquesArrayList().remove(targetClique);
*
* String[] cliqueNodesNames=targetClique.getName().split("/");
*
* while (indexNodeNames<cliqueNodesNames.length){
*
* String tempName=cliqueNodesNames[indexNodeNames];
*
* Node tempNode=CliqueOperations.searchNode(tempName,tempNodes); String[]
* bayesletAndNode=tempName.split(":"); String
* bayesletName=bayesletAndNode[0]; Bayeslet
* current=CliqueOperations.searchBayeslet(bayesletName, bayeslets);
* Bayeslet backUp=CliqueOperations.searchBayeslet(bayesletName,
* backUpBayeslets);
*
* if
* ((tempName.contains("-"))&&(tempNode.getParentClique().equals(targetClique
* ))){ allDissolvedNodes.addAll(this.dissolveCombinedNodeClique(tempName,
* bayeslets, backUpBayeslets));
*
* } indexNodeNames++; } int indexADN=0; System.out.println("Pasa o q");
*
* while (indexADN<allDissolvedNodes.size()){
*
* Node temp=(Node) allDissolvedNodes.get(indexADN); String[]
* tempIDBLNode=temp.getName().split(":"); String
* bayesletName=tempIDBLNode[0]; Bayeslet
* backUpBayeslet=CliqueOperations.searchBayeslet(bayesletName,
* backUpBayeslets); Node backUpNode =
* backUpBayeslet.getNode(temp.getName());
*
* Clique backUp = backUpNode.getParentClique(); Node[]
* tempPar=backUp.getParticipants(); Node[] newCliqueNodes=new
* Node[tempPar.length]; int indexPar=0;
*
* while (indexPar<tempPar.length){ Node tempNode=tempPar[indexPar]; Node
* newNode=CliqueOperations.searchNode(tempNode.getName(),this.getNodes());
* newCliqueNodes[indexPar]=newNode; indexPar++; }
*
* Clique newClique=new Clique(newCliqueNodes); this.cliques.add(newClique);
*
* ArrayList tempSep=backUp.getUndirectedEdges();
*
*
*
*
* indexADN++; }
*
*
* indexNodeNames=0;
*
* while (indexNodeNames<cliqueNodesNames.length){
*
* String tempName=cliqueNodesNames[indexNodeNames]; Node
* tempNode=CliqueOperations.searchNode(tempName,tempNodes); Clique
* tempParent=tempNode.getParentClique();
*
*
* if (tempParent.equals(targetClique)){
*
* String[] bayesletAndNode=tempName.split(":");
*
* String bayesletName=bayesletAndNode[0];
*
* Bayeslet current=CliqueOperations.searchBayeslet(bayesletName,
* bayeslets); Bayeslet backUp=CliqueOperations.searchBayeslet(bayesletName,
* backUpBayeslets);
*
* //this.resetClique(tempParent,current,backUp); } indexNodeNames++; }
*
* }
*
* /*public void resetClique(Clique currentClique,Bayeslet current,Bayeslet
* backupBayeslet){
*
* String cliqueName=currentClique.getName(); ArrayList
* backUpCliques=backupBayeslet.getJunctionTree().getCliquesArrayList(); int
* backUpCliquePos= CliqueOperations.searchPosition(cliqueName,
* backUpCliques); Clique backUpClique=(Clique)
* backUpCliques.get(backUpCliquePos); }
*/
/*
*
* public void transferEdgesBackUp(Node backUpNode, Node target){
*
* ArrayList combinedEdges=this.getEdges();
*
* ArrayList combinedNodes=this.getNodes();
*
*
* int index=0; Edge tempEdge; Edge newEdge; ArrayList tempIncoming;
* ArrayList tempOutgoing; tempIncoming=backUpNode.getIncoming();
*
* while (index<tempIncoming.size()){
* tempEdge=(Edge)tempIncoming.get(index); String
* tempSourceName=tempEdge.getSource().getName(); Node
* edgeSource=CliqueOperations.searchNode(tempSourceName, combinedNodes);
* newEdge=new Edge(edgeSource,target);
* //tempEdge.getSource().removeOutgoing(tempEdge);
*
* //target.addIncoming(newEdge); combinedEdges.add(newEdge);
* combinedEdges.remove(tempEdge); index++; } index=0;
*
* tempOutgoing=backUpNode.getOutgoing();
*
* while (index<tempOutgoing.size()){
* tempEdge=(Edge)tempOutgoing.get(index); String
* tempTargetName=tempEdge.getTarget().getName(); Node
* edgeTarget=CliqueOperations.searchNode(tempTargetName, combinedNodes);
* newEdge=new Edge(target,edgeTarget);
* //tempEdge.getTarget().removeIncoming(tempEdge);
*
* combinedEdges.add(newEdge); combinedEdges.remove(tempEdge); index++; }
*
* }
*
* public ArrayList dissolveCombinedNodeClique(String name,Bayeslet[]
* bayeslets,Bayeslet[] backUpBayeslets){
*
* ArrayList dissolvedNodes=new ArrayList(); ArrayList
* combinedNodes=this.getNodes(); Node
* toBeRemoved=CliqueOperations.searchNode(name, combinedNodes);
*
* combinedNodes.remove(toBeRemoved);
*
* String[]combinedNodeNames=toBeRemoved.getName().split("-"); int
* indexCombinedNodes=0;
*
* while(indexCombinedNodes<combinedNodeNames.length){
*
* String nodeName=combinedNodeNames[indexCombinedNodes]; String[]
* bayesletAndNode=combinedNodeNames[indexCombinedNodes].split(":"); String
* bayesletName=bayesletAndNode[0];
*
* Bayeslet current=CliqueOperations.searchBayeslet(bayesletName,
* bayeslets); Bayeslet backUp=CliqueOperations.searchBayeslet(bayesletName,
* backUpBayeslets);
*
* InterfaceNodeRecord tempINR=current.getInterfaceNodeInfo(nodeName);
*
* dissolvedNodes.add(this.resetNodeClique(nodeName,backUp,current,tempINR.
* isIncomingInterfaceNode()));
*
* tempINR.setToBeUpdated(true);
*
* indexCombinedNodes++; } return (dissolvedNodes); }
*
* public Node resetNodeClique(String connectedNodeName, Bayeslet
* backUpBayeslet,Bayeslet current,boolean incomingInterfaceNode){
*
*
* Node backUpNode= backUpBayeslet.getNode(connectedNodeName); Node newNode=
* new Node(backUpNode.getName(),backUpNode.getStates());
*
* CliqueOperations.transferEdgesBackUp(backUpNode, newNode,
* this.getNodes(),this.getEdges()); Probability[] temp =
* backUpNode.getProbTable().getProbabilities();
* newNode.setProbDistribution(
* backUpNode.getProbTable().getProbabilities());
*
* Node currentNode = current.getNode(connectedNodeName);
*
* currentNode.setName(connectedNodeName);
* currentNode.setProbDistribution(backUpNode
* .getProbTable().getProbabilities());
*
* if (incomingInterfaceNode) {
* CliqueOperations.transferEdgesBackUp(backUpNode, currentNode,
* current.getDAG().getNodesArrayList(),current.getDAG().getNodesArrayList
* ()); }
*
* this.getNodes().add(newNode); return (newNode); }
*/
/**
* It adds cliques to the set of cliques contained in the junction tree.
*
* @param newCliques
* ArrayList containing the cliques to be added.
*/
/*
* public void addCliques(ArrayList newCliques){
*
* int index=0; while(index<newCliques.size()){
* this.cliques.add(newCliques.get(index)); index++; }
*
* }
*/
/**
* This method adds a separator to the set of cliques contained in the
* junction tree.
*
* @param newSeparator
*/
/*
*
* public void addSeparator(Separator newSeparator){
*
* this.separators.add(newSeparator);
*
* }
*/
/**
* This method adds a set of separators to the set of separator contained in
* the junction tree.
*
* @param input
*/
/*
* public void addSeparators(ArrayList input){
*
* int index=0; while(index<input.size()){
* this.separators.add(input.get(index)); index++; } }
*/
/*
* public void addEdges(ArrayList input){ this.edges.addAll(input); }
*/
/*
* public void addNodes(ArrayList input){ nodes.addAll(input); }
*/
/**
* This method modifies the label from a separator, exchanging the source
* node with the target node.
*
* @param sourceNode
* @param targetNode
* @param input
*/
/*
* public void updateSeparatorLabel(Node sourceNode, Node targetNode,Node[]
* input){
*
* ArrayList inputA=CliqueOperations.arrayToArrayList(input); Node
* temp=CliqueOperations.searchNode(sourceNode.getName(),inputA);
* temp=targetNode; input=CliqueOperations.convertToArray(inputA);
*
* }
*/
}