package org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.impl; import java.util.ArrayList; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.interfaces.ConnectingNodes; import org.societies.context.user.refinement.impl.bayesianLibrary.inference.structures.interfaces.HasProbabilityTable; /** * @author fran_ko * */ public class Node implements Comparable, HasProbabilityTable { private ArrayList incoming = new ArrayList(); private ArrayList outgoing = new ArrayList(); private ArrayList undirectedConnections = new ArrayList(); private Clique parentClique = null; protected String name; protected String[] states; private ProbabilityDistribution prob; private ProbabilityDistribution marginalization; private ProbabilityDistribution likelihood; private boolean unobserved; private static Logger logger = LoggerFactory.getLogger(Node.class); public Node(String variableName, String[] states){ name = variableName; this.states = states; } /** * FOR USE IN CLIQUE; * */ public Node(){ } /** * Core idea: Run through the marginalisation. with hard evidence, only one value can be above 0. * -> a positive value is marked, the second positive value already returns false then. * * @return */ public boolean hasHardEvidence() { boolean onePositive = false; Probability[] marginalizedProbs = marginalization.getProbabilities(); for(Probability p: marginalizedProbs) { if (p.getProbability()>0) if (onePositive) return false; else onePositive = true; } if (!onePositive) logger.error("All values are 0!"); return onePositive; } public void setName(String name){ this.name=name; } public void setProbDistribution(Probability[] twoDimensionalFixedOrder){ int testLength = 1; for(int i=0; i<getParticipants().length;i++){ testLength*=getParticipants()[i].countStates(); } if (twoDimensionalFixedOrder!=null && twoDimensionalFixedOrder.length == testLength && twoDimensionalFixedOrder[0].getStates().length == (getParticipants().length)) prob = new ProbabilityDistribution(this, twoDimensionalFixedOrder); else { logger .error("Node: setProbDistribution(Probability[]): Probability Table does not fit the structure of the network"); // System.out.println(twoDimensionalFixedOrder.length); } } public void setProbDistribution(double[] pureProbs){ int testLength = countStates(); for (int i=0; i<incoming.size();i++){ Edge e = (Edge)incoming.get(i); testLength*=e.source.countStates(); } if (pureProbs!=null && pureProbs.length == testLength) { prob = new ProbabilityDistribution(this, pureProbs); } else{ /* Testing: * System.err.println(pureProbs + ", Lange: "+pureProbs.length+ ", #parents: "+incoming.size()+", testLength="+testLength); */ logger.error("Probability Table does not fit the structure of the network"); } } public ArrayList getIncoming(){ return incoming; } public ArrayList getOutgoing(){ return outgoing; } public ArrayList getUndirectedEdges(){ return undirectedConnections; } public String getName(){ return name; } public String[] getStates(){ return states; } /** * also known as WEIGHT of this node * @return */ public int countStates(){ return states.length; } /* (non-Javadoc) * @see structures.ProbabilityTable#getProbTable() */ public ProbabilityDistribution getProbTable() { return prob; } /** * @param dag */ public void updateProbTable(DAG dag) { // TODO Implementation of an updated Probability Table } /** * @param e */ public void addIncoming(Edge e) { incoming.add(e); } /** * @param e */ public void addOutgoing(Edge e) { outgoing.add(e); } /** * @param e */ public void removeIncoming(Edge e) { incoming.remove(e); } /** * @param e */ public void addConnection(ConnectingNodes e) { undirectedConnections.add(e); } /** * @param e */ public void removeConnection(ConnectingNodes e) { undirectedConnections.remove(e); } /** * @param e */ public void removeOutgoing(Edge e) { outgoing.remove(e); } public String toString(){ return name; } /** * @return this node and all nodes connected to him public Node[] getNeighbours(){ Node[] result = new Node[1+incoming.size()+outgoing.size()+undirectedConnections.size()]; int j = 0; result[j++] = this; for (int i=0;i<incoming.size();i++) { Node n = ((Edge) incoming.get(i)).getSource(); result[j++]=n; } for (int i=0;i<outgoing.size();i++) { Node n = ((Edge) outgoing.get(i)).getTarget(); result[j++]=n; } for (int i=0;i<undirectedConnections.size();i++) { UndirectedEdge e = (UndirectedEdge) undirectedConnections.get(i); Node n = (e.getBorder1().equals(this))? e.getBorder2() : e.getBorder1(); result[j++]=n; } return result; } */ /** * @return all nodes connected to this node (This node NOT included) */ public Node[] getNeighbours(){ Node[] result = new Node[incoming.size()+outgoing.size()+undirectedConnections.size()]; int j = 0; for (int i=0;i<incoming.size();i++) { Node n = ((Edge) incoming.get(i)).getSource(); result[j++]=n; } for (int i=0;i<outgoing.size();i++) { Node n = ((Edge) outgoing.get(i)).getTarget(); result[j++]=n; } for (int i=0;i<undirectedConnections.size();i++) { ConnectingNodes e = (ConnectingNodes) undirectedConnections.get(i); Node n = (e.getBorder1().equals(this))? e.getBorder2() : e.getBorder1(); result[j++]=n; } return result; } /* (non-Javadoc) * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int compareTo(Object arg0) { return name.compareTo(((Node)arg0).getName()); } /** * The Node itself + its parents * * @see de.dlr.kn.bayesianLibrary.inference.structures.interfaces.personalsmartspaces.cm.reasoning.bayesian.structures.HasProbabilityTable#getParticipants() */ public Node[] getParticipants() { Node[] result = new Node[1+incoming.size()]; result[0] = this; for (int i=0;i<incoming.size();i++) { Node n = ((Edge) incoming.get(i)).getSource(); result[i+1]=n; } return result; } /** * assigns the family of this node to a clique that is representing it * * @param cliques - all available cliques/clusters */ public Clique assignClique(ArrayList cliques) { ArrayList family = new ArrayList(Arrays.asList(getParticipants())); for (int i=0;i<cliques.size();i++) { Clique current = (Clique)cliques.get(i); ArrayList cliqueMembers = new ArrayList(Arrays.asList(current.getParticipants())); if(cliqueMembers.containsAll(family)){ parentClique = current; // System.out.println("Node: " + name + ", parent Clique: " + parentClique); return current; } } logger.error("Node:assignClique(ArrayList): run through all cliques, but no parent one for Node "+this); return null; } public Clique getParentClique(){ return parentClique; } /** * @param distribution constructed by the method call marginalize(Node n) * @see org.personalsmartspaces.cm.reasoning.bayesian.solving.JunctionTree#marginalize(Node n) */ public void setMarginalization(ProbabilityDistribution distribution) { marginalization = distribution; } /** * @return marginalisation */ public ProbabilityDistribution getMarginalization() { return marginalization; } public String printMarginalization(){ if (marginalization == null) return null; return marginalization.toString(); } /** * Sets the Likelihood-Table of this node to 1. * Likelihood is represented by the private instance field "likelihood" and * represented as a ProbabilityDistribution, for each state is assigned a Probability */ public void initializeObservation() { Probability[] neu = new Probability[states.length]; for(int i=0;i<neu.length;i++){ String[] temp = {states[i]}; neu[i] = new Probability(temp,1); } likelihood = new ProbabilityDistribution(this, neu); unobserved = true; } public ProbabilityDistribution setObservation(String[] states, double[] probabilities){ unobserved = true; if (!(states.length==probabilities.length)){ logger.error("Node: SetObservation - Wrong Data"); return null; } double probSum = 0; for (int i=0;i<probabilities.length;i++){ probSum+=probabilities[i]; if (probabilities[i]!=1) unobserved=false; } if (unobserved) return null; if (probSum!=1){ //normalizing the probability vector so that sum = 1 double quotient = 1 / probSum; for (int i=0;i<probabilities.length;i++){ probabilities[i]*=quotient; } } /* * Lambda_V = Lambda_V * Lambda_V^new */ Node[] self = {this}; for (int i=0;i<states.length;i++){ String[] state_array = {states[i]}; int[] toChange = likelihood.fitsIndex(self, state_array); if (!(toChange.length==1)){ logger.error("Node: SetObservation - Value unknown; toChange.length="+toChange.length + " Node: "+name); logger.error("State_Array = ["+states[i]+"]"); logger.error(likelihood.toString()); for (int j=0;j<toChange.length;j++) logger.error(toChange[j]+""); } Probability change = likelihood.getProbabilities()[toChange[0]]; change.multiplyProbability(probabilities[i]); } return likelihood; } public void setObservation(ProbabilityDistribution readyList){ likelihood = readyList; } public ProbabilityDistribution getObservation(){ return likelihood; } //ADDED by Maria: public String getHardEvidence(){ String state; int index = 0; int counter = 0; for(int i=0;i<this.likelihood.getProbabilities().length;i++){ if(likelihood.getProbabilities()[i].getProbability()==1){ counter++; index = i; } } if (counter>1){ System.out.println("ERROR!! The node was not observed or it does not have a HARD EVIDENCE!!"); return null; } state = this.getStates()[index]; return state; } //End added by Maria }