package org.societies.context.user.refinement.impl.bayesianLibrary.bayesianLearner.impl;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import org.societies.context.user.refinement.impl.bayesianLibrary.bayesianLearner.interfaces.BayesianProbabilitiesEstimator;
import org.societies.context.user.refinement.impl.bayesianLibrary.bayesianLearner.interfaces.Candidate;
import org.societies.context.user.refinement.impl.bayesianLibrary.bayesianLearner.interfaces.CandidatesGenerator;
import org.societies.context.user.refinement.impl.bayesianLibrary.bayesianLearner.interfaces.RandomVariable;
/**
* This class contains the Enumeration generator for producing new Candidate BNs.
* @author robert_p
*
*/
public class BayesianNetworkCandidatesGenerator implements CandidatesGenerator{
private CandidateEnumeration enumeration;
private BayesianProbabilitiesEstimator bpe;
private Set<RandomVariable> allnodesset;
private int maxNumberParentsPerNode;
//private int maxNumberSonsPerNode;
public BayesianNetworkCandidatesGenerator(BayesianProbabilitiesEstimator bpe, Set<RandomVariable> allnodesset, int maxNumberParentsPerNode) {
this.enumeration = new CandidateEnumeration(bpe);
this.bpe = bpe;
this.maxNumberParentsPerNode = maxNumberParentsPerNode;
this.allnodesset = new HashSet<RandomVariable>(allnodesset);
}
public Enumeration returnEnumerationOverModifiedCandidates() {
this.enumeration.reset();
return this.enumeration;
}
public void initialise(Candidate startingCandidate) {
if (startingCandidate instanceof BayesianNetworkCandidate) {
this.enumeration.baseBN.importFrom((BayesianNetworkCandidate) startingCandidate);
}
else throw new IllegalArgumentException("\n Cannot initialize BayesianNetworkCandidate from " + startingCandidate.getClass());
}
/**
* This inner class is the Enumeration that does the work of returning BayesianNetworkCandidates
* by starting with the BayesianNetworkCandidate baseBN that is set during
* initialise(Candidate startingCandidate) in the outer class, and adding and removing and
* swapping arcs.
*
* @author robert_p
*
*/
private class CandidateEnumeration implements Enumeration{
private RandomVariable[] arc_target_array;
private int state;
private static final int InitState = 0;
private static final int AddingArcsState = 1;
private static final int RemovingArcsState = 2;
private static final int SwappingOrderOfArcsState = 3;
private static final int FinishedState = 4;
private BayesianNetworkCandidate baseBN;
private boolean xx_willstop = false;
private int target_counter;
private RandomVariable[] arc_source_array;
private int source_counter;
/**
*@see java.lang.Object#Object()
*/
public CandidateEnumeration(BayesianProbabilitiesEstimator bpe) {
this.baseBN = new BayesianNetworkCandidate(bpe, maxNumberParentsPerNode);
}
// TODO: fix problem with enumeration returning null if there are no arcs to delete and none to swap!
public boolean hasMoreElements() {
return (! (this.state == CandidateEnumeration.FinishedState));
}
/**
* This resets the class before we can return new candidates from a fresh Enumeration.
*/
public void reset() {
this.state = CandidateEnumeration.InitState;
// System.out.println(" Beginning with Enumeration. Basis is: \n" + this.baseBN);
}
/* (non-Javadoc)
* This method starts by returning all candidates with a new added arc, then removed
* arcs, then swapped arcs.
* @see java.util.Enumeration#nextElement()
*/
public Object nextElement() {
//System.out.println(" getting next element, state is: " + this.state);
if (this.state == InitState) {
this.target_counter = 0;
this.source_counter = 0;
this.state = AddingArcsState;
} else {
this.baseBN.rollbackLastOperation();
}
if (this.state == AddingArcsState) {
BayesianNetworkCandidate nextcandidate = this.returnNextAddedArc();
if (nextcandidate != null) {
return nextcandidate;
}
else {
// if (1.0/this.baseBN.getSecondaryFitness() > 4.0) { // test for more that 4 arcs
// System.out.println("\n\n\n\n\n Will stop soon with getSecondaryFitness "+
// this.baseBN.getSecondaryFitness() + " and with score: " + this.baseBN.score + "\n" + this.baseBN);
// this.xx_willstop = true;
// // System.exit(0);
// }
this.target_counter = -1;
this.source_counter = -1;
this.state = RemovingArcsState;
}
}
if (this.state == RemovingArcsState) {
// System.out.println(" 22 getting next element, state is: " + this.state + " "+ this.target_counter + " " + this.source_counter);
BayesianNetworkCandidate nextcandidate = this.returnNextRemovedArc();
if (nextcandidate != null) {
return nextcandidate;
}
else {
this.target_counter = -1;
this.source_counter = -1;
// if (this.xx_willstop) System.exit(-1);
this.state = SwappingOrderOfArcsState;
}
}
if (this.state == SwappingOrderOfArcsState) {
// System.out.println(" 33 getting next element, state is: " + this.state + " "+ this.target_counter + " " + this.source_counter);
if (!this.hasMoreArcsToSwap()) {
this.state = FinishedState;
// System.out.println(" 44 getting next element, state is: " + this.state + " "+ this.target_counter + " " + this.source_counter);
}
else {
return this.returnNextSwappedArc();
}
}
return null;
}
private BayesianNetworkCandidate returnNextAddedArc() {
// TODO try and be more efficient when detecting that arc added to itself
// TODO try and be more efficient when detecting that arc already present
if (!computeNext_RV_and_Arc_to_Add()) return null;
int current_size_of_target_node_parent_set =
this.baseBN.getBNSegment(this.arc_target_array[this.target_counter]).
getOrderedParents().size();
if (current_size_of_target_node_parent_set >= maxNumberParentsPerNode) {
this.source_counter++;
return this.baseBN;
}
/*if (this.baseBN.getBNSegment(this.arc_source_array[this.source_counter]).
getTargetRV().doesNotAllowOutgoingArrows()) return this.baseBN;
if (this.baseBN.getBNSegment(this.arc_target_array[this.target_counter]).
getTargetRV().allowsOnlyOutgoingArrows()) return this.baseBN;*/
//if (current_size_of_target_node_parent_set >= maxNumberParentsPerNode) return this.baseBN;
// System.out.println("Adding an arc");
return this.baseBN.addArc(this.arc_target_array[this.target_counter], this.arc_source_array[this.source_counter++]);
}
private BayesianNetworkCandidate returnNextRemovedArc() {
if (!computeNext_RV_and_Arc_to_Remove_or_Swap()) return null;
else {
// System.out.println("Removing an arc");
return this.baseBN.removeArc(this.arc_target_array[this.target_counter],
this.arc_source_array[this.source_counter]);
}
}
private BayesianNetworkCandidate returnNextSwappedArc() {
// System.out.println("Swapping an arc");
/*ADDED by Maria:
*
*At the outset, the source node is a parent of the target node. In this method,
*the other combination should be checked in order to see if the score is bigger
*or not.
*
*The problem is that, as we would like to limit the number of parents, first
*we have to check if the source node has already a complete parent set, meaning,
*the maximum number of parents possible. If it has it, the target node cannot become
*a parent. This condition is checked by the next part of the code. If it is not possible
*to swap the arc, it will return that base BN.
*
* */
//ADDED by Maria:
int current_size_of_source_node_parent_set =
this.baseBN.getBNSegment(this.arc_source_array[this.source_counter]).
getOrderedParents().size();
if (current_size_of_source_node_parent_set >= maxNumberParentsPerNode) return this.baseBN;
//END "added by Maria"
/*if (this.baseBN.getBNSegment(this.arc_source_array[this.source_counter]).
getTargetRV().allowsOnlyOutgoingArrows()) return this.baseBN;
if (this.baseBN.getBNSegment(this.arc_target_array[this.target_counter]).
getTargetRV().doesNotAllowOutgoingArrows()) return this.baseBN;*/
return this.baseBN.swapArc(this.arc_target_array[this.target_counter],
this.arc_source_array[this.source_counter]);
}
private boolean computeNext_RV_and_Arc_to_Add() {
// TODO merge with computeNext_RV_and_Arc_to_Remove_or_Swap
if (this.target_counter==0) {
this.arc_target_array = (RandomVariable[]) this.baseBN.getSegments().keySet().toArray(new RandomVariable[0]);
this.arc_source_array = (RandomVariable[]) this.baseBN.getSegments().keySet().toArray(new RandomVariable[0]);
}
if (this.source_counter==this.arc_source_array.length) {
this.source_counter = 0;
this.target_counter++;
}
if (this.target_counter==this.arc_target_array.length) {
// System.out.println("In computeNext_RV_and_Arc_to_Add. Finished. this.target_counter: " +
// this.target_counter + " this.arc_target_array.length " + this.arc_target_array.length + " this.source_counter " + this.source_counter);
return false;
}
// System.out.println("In computeNext_RV_and_Arc_to_Add. this.target_counter: " +
// this.target_counter + " this.arc_target_array.length " + this.arc_target_array.length + " this.source_counter " + this.source_counter);
return true;
}
private boolean computeNext_RV_and_Arc_to_Remove_or_Swap() {
if (this.target_counter<0) {
this.arc_target_array = (RandomVariable[]) this.baseBN.getSegments().keySet().toArray(new RandomVariable[0]);
this.target_counter++;
}
do {
source_counter++;
if (source_counter==0) {
BNSegment bns = (BNSegment) this.baseBN.getSegments().get(this.arc_target_array[target_counter]);
this.arc_source_array = (RandomVariable[]) bns.getOrderedParents().toArray(new RandomVariable[0]);
}
// System.out.println("In computeNext_RV_and_Arc_to_Remove_or_Swap. In do while loop . this.target_counter: " +
// this.target_counter + " this.arc_target_array.length " +
// this.arc_target_array.length + " this.source_counter " + this.source_counter +
// " arc_source_array length: " + this.arc_source_array.length );
if (this.source_counter==this.arc_source_array.length) {
this.target_counter++;
source_counter = -1;
}
if (this.target_counter==this.arc_target_array.length) {
// System.out.println("In computeNext_RV_and_Arc_to_Remove_or_Swap. Finished . this.target_counter: " +
// this.target_counter + " this.arc_target_array.length " + this.arc_target_array.length + " this.source_counter " + this.source_counter);
return false;
}
}
while (source_counter == -1);
// System.out.println("In computeNext_RV_and_Arc_to_Remove_or_Swap. this.target_counter: " +
// this.target_counter + " this.arc_target_array.length " + this.arc_target_array.length + " this.source_counter " + this.source_counter);
return true;
}
private boolean hasMoreArcsToSwap() {
return (this.computeNext_RV_and_Arc_to_Remove_or_Swap());
}
}
public Candidate makeStartingCandidate() {
if (this.enumeration.baseBN != null) return this.enumeration.baseBN;
return new BayesianNetworkCandidate(this.bpe, this.allnodesset, this.maxNumberParentsPerNode);
}
public Candidate makeEmptyCandidate() {
return new BayesianNetworkCandidate(this.bpe, this.maxNumberParentsPerNode);
}
}