/** * Help determine if one event is conditionally independent of another. * * @param previousHead The previous head, as we traverse the list. * @param a The event to check. * @param goal The goal. * @param searched List of events searched. * @param given Given events. * @return True if conditionally independent. */ private boolean isCondIndependent( boolean previousHead, BayesianEvent a, BayesianEvent goal, Set<BayesianEvent> searched, BayesianEvent... given) { // did we find it? if (a == goal) { return false; } // search children for (BayesianEvent e : a.getChildren()) { if (!searched.contains(e) || !isGiven(given, a)) { searched.add(e); if (!isCondIndependent(true, e, goal, searched, given)) return false; } } // search parents for (BayesianEvent e : a.getParents()) { if (!searched.contains(e)) { searched.add(e); if (!previousHead || isGivenOrDescendant(given, a)) if (!isCondIndependent(false, e, goal, searched, given)) return false; } } return true; }
/** @return The number of parameters in this Bayesian network. */ public int calculateParameterCount() { int result = 0; for (BayesianEvent e : this.eventMap.values()) { result += e.calculateParameterCount(); } return result; }
/** * Remove the specified event. * * @param event The event to remove. */ private void removeEvent(BayesianEvent event) { for (BayesianEvent e : event.getParents()) { e.getChildren().remove(event); } this.eventMap.remove(event.getLabel()); this.events.remove(event); }
/** * Classify the input. * * @param input The input to classify. */ @Override public int classify(MLData input) { if (this.classificationTarget < 0 || this.classificationTarget >= this.events.size()) { throw new BayesianError( "Must specify classification target by calling setClassificationTarget."); } int[] d = this.determineClasses(input); // properly tag all of the events for (int i = 0; i < this.events.size(); i++) { BayesianEvent event = this.events.get(i); if (i == this.classificationTarget) { this.query.defineEventType(event, EventType.Outcome); } else if (this.inputPresent[i]) { this.query.defineEventType(event, EventType.Evidence); this.query.setEventValue(event, d[i]); } else { this.query.defineEventType(event, EventType.Hidden); this.query.setEventValue(event, d[i]); } } // loop over and try each outcome choice BayesianEvent outcomeEvent = this.events.get(this.classificationTarget); this.classificationProbabilities = new double[outcomeEvent.getChoices().size()]; for (int i = 0; i < outcomeEvent.getChoices().size(); i++) { this.query.setEventValue(outcomeEvent, i); this.query.execute(); classificationProbabilities[i] = this.query.getProbability(); } return EngineArray.maxIndex(this.classificationProbabilities); }
/** * @return Returns a string representation of the classification structure. Of the form P(a|b,c,d) */ public String getClassificationStructure() { StringBuilder result = new StringBuilder(); result.append("P("); boolean first = true; for (int i = 0; i < this.getEvents().size(); i++) { BayesianEvent event = this.events.get(i); EventState state = this.query.getEventState(event); if (state.getEventType() == EventType.Outcome) { if (!first) { result.append(","); } result.append(event.getLabel()); first = false; } } result.append("|"); first = true; for (int i = 0; i < this.getEvents().size(); i++) { BayesianEvent event = this.events.get(i); if (this.query.getEventState(event).getEventType() == EventType.Evidence) { if (!first) { result.append(","); } result.append(event.getLabel()); first = false; } } result.append(")"); return result.toString(); }
/** * Create a dependency between two events. * * @param parentEvent The parent event. * @param childEvent The child event. */ public void createDependency(BayesianEvent parentEvent, BayesianEvent childEvent) { // does the dependency exist? if (!hasDependency(parentEvent, childEvent)) { // create the dependency parentEvent.addChild(childEvent); childEvent.addParent(parentEvent); } }
/** * Create, or register, the specified event with this bayesian network. * * @param event The event to add. */ public void createEvent(BayesianEvent event) { if (eventExists(event.getLabel())) { throw new BayesianError("The label \"" + event.getLabel() + "\" has already been defined."); } this.eventMap.put(event.getLabel(), event); this.events.add(event); }
/** * Determine the classes for the specified input. * * @param input The input. * @return An array of class indexes. */ public int[] determineClasses(MLData input) { int[] result = new int[input.size()]; for (int i = 0; i < input.size(); i++) { BayesianEvent event = this.events.get(i); int classIndex = event.matchChoiceToRange(input.getData(i)); result[i] = classIndex; } return result; }
/** {@inheritDoc} */ public String toString() { StringBuilder result = new StringBuilder(); boolean first = true; for (BayesianEvent e : this.events) { if (!first) result.append(" "); first = false; result.append(e.toString()); } return result.toString(); }
/** Finalize the structure of this Bayesian network. */ public void finalizeStructure() { for (BayesianEvent e : this.eventMap.values()) { e.finalizeStructure(); } if (this.query != null) { this.query.finalizeStructure(); } this.inputPresent = new boolean[this.events.size()]; EngineArray.fill(this.inputPresent, true); this.classificationTarget = -1; }
public void testSampling3() { BayesianNetwork network = new BayesianNetwork(); BayesianEvent a = network.createEvent("a"); BayesianEvent x1 = network.createEvent("x1"); BayesianEvent x2 = network.createEvent("x2"); BayesianEvent x3 = network.createEvent("x3"); network.createDependancy(a, x1, x2, x3); network.finalizeStructure(); a.getTable().addLine(0.5, true); // P(A) = 0.5 x1.getTable().addLine(0.2, true, true); // p(x1|a) = 0.2 x1.getTable().addLine(0.6, true, false); // p(x1|~a) = 0.6 x2.getTable().addLine(0.2, true, true); // p(x2|a) = 0.2 x2.getTable().addLine(0.6, true, false); // p(x2|~a) = 0.6 x3.getTable().addLine(0.2, true, true); // p(x3|a) = 0.2 x3.getTable().addLine(0.6, true, false); // p(x3|~a) = 0.6 network.validate(); SamplingQuery query = new SamplingQuery(network); query.defineEventType(x1, EventType.Evidence); query.defineEventType(x3, EventType.Outcome); query.setEventValue(x1, true); query.setEventValue(x3, true); query.execute(); testPercent(query.getProbability(), 50); }
/** * Determine if one event is a descendant of another. * * @param a The event to check. * @param b The event that has children. * @return True if a is amoung b's children. */ public boolean isDescendant(BayesianEvent a, BayesianEvent b) { if (a == b) return true; for (BayesianEvent e : b.getChildren()) { if (isDescendant(a, e)) return true; } return false; }
public void testSampling1() { BayesianNetwork network = new BayesianNetwork(); BayesianEvent a = network.createEvent("a"); BayesianEvent b = network.createEvent("b"); network.createDependancy(a, b); network.finalizeStructure(); a.getTable().addLine(0.5, true); // P(A) = 0.5 b.getTable().addLine(0.2, true, true); // p(b|a) = 0.2 b.getTable().addLine(0.8, true, false); // p(b|~a) = 0.8 network.validate(); SamplingQuery query = new SamplingQuery(network); query.defineEventType(a, EventType.Evidence); query.defineEventType(b, EventType.Outcome); query.setEventValue(b, true); query.setEventValue(a, true); query.execute(); testPercent(query.getProbability(), 20); }
/** Validate the structure of this Bayesian network. */ public void validate() { for (BayesianEvent e : this.eventMap.values()) { e.validate(); } }
/** {@inheritDoc} */ @Override public final void save(final OutputStream os, final Object obj) { final EncogWriteHelper out = new EncogWriteHelper(os); final BayesianNetwork b = (BayesianNetwork) obj; out.addSection("BAYES-NETWORK"); out.addSubSection("BAYES-PARAM"); String queryType = ""; String queryStr = b.getClassificationStructure(); if (b.getQuery() != null) { queryType = b.getQuery().getClass().getSimpleName(); } out.writeProperty("queryType", queryType); out.writeProperty("query", queryStr); out.writeProperty("contents", b.getContents()); out.addSubSection("BAYES-PROPERTIES"); out.addProperties(b.getProperties()); out.addSubSection("BAYES-TABLE"); for (BayesianEvent event : b.getEvents()) { for (TableLine line : event.getTable().getLines()) { if (line == null) continue; StringBuilder str = new StringBuilder(); str.append("P("); str.append(BayesianEvent.formatEventName(event, line.getResult())); if (event.getParents().size() > 0) { str.append("|"); } int index = 0; boolean first = true; for (BayesianEvent parentEvent : event.getParents()) { if (!first) { str.append(","); } first = false; int arg = line.getArguments()[index++]; if (parentEvent.isBoolean()) { if (arg == 0) { str.append("+"); } else { str.append("-"); } } str.append(parentEvent.getLabel()); if (!parentEvent.isBoolean()) { str.append("="); if (arg >= parentEvent.getChoices().size()) { throw new BayesianError( "Argument value " + arg + " is out of range for event " + parentEvent.toString()); } str.append(parentEvent.getChoice(arg)); } } str.append(")="); str.append(line.getProbability()); str.append("\n"); out.write(str.toString()); } } out.flush(); }
/** * Determine if the two events have a dependency. * * @param parentEvent The parent event. * @param childEvent The child event. * @return True if a dependency exists. */ private boolean hasDependency(BayesianEvent parentEvent, BayesianEvent childEvent) { return (parentEvent.getChildren().contains(childEvent)); }
/** * Create a dependency between a parent and multiple children. * * @param parentEvent The parent event. * @param children The child events. */ public void createDependency(BayesianEvent parentEvent, BayesianEvent... children) { for (BayesianEvent childEvent : children) { parentEvent.addChild(childEvent); childEvent.addParent(parentEvent); } }
/** * Define the structure of the Bayesian network as a string. * * @param line The string to define events and relations. */ public void setContents(String line) { List<ParsedProbability> list = ParseProbability.parseProbabilityList(this, line); List<String> labelList = new ArrayList<String>(); // ensure that all events are there for (ParsedProbability prob : list) { ParsedEvent parsedEvent = prob.getChildEvent(); String eventLabel = parsedEvent.getLabel(); labelList.add(eventLabel); // create event, if not already here BayesianEvent e = getEvent(eventLabel); if (e == null) { List<BayesianChoice> cl = new ArrayList<BayesianChoice>(); for (ParsedChoice c : parsedEvent.getList()) { cl.add(new BayesianChoice(c.getLabel(), c.getMin(), c.getMax())); } createEvent(eventLabel, cl); } } // now remove all events that were not covered for (int i = 0; i < events.size(); i++) { BayesianEvent event = this.events.get(i); if (!labelList.contains(event.getLabel())) { removeEvent(event); } } // handle dependencies for (ParsedProbability prob : list) { ParsedEvent parsedEvent = prob.getChildEvent(); String eventLabel = parsedEvent.getLabel(); BayesianEvent event = requireEvent(eventLabel); // ensure that all "givens" are present List<String> givenList = new ArrayList<String>(); for (ParsedEvent given : prob.getGivenEvents()) { if (!event.hasGiven(given.getLabel())) { BayesianEvent givenEvent = requireEvent(given.getLabel()); this.createDependency(givenEvent, event); } givenList.add(given.getLabel()); } // now remove givens that were not covered for (int i = 0; i < event.getParents().size(); i++) { BayesianEvent event2 = event.getParents().get(i); if (!givenList.contains(event2.getLabel())) { removeDependency(event2, event); } } } // finalize the structure finalizeStructure(); if (this.query != null) { this.query.finalizeStructure(); } }
/** {@inheritDoc} */ @Override public void reset(int seed) { for (BayesianEvent event : this.events) { event.reset(); } }
/** Remove all relations between nodes. */ public void removeAllRelations() { for (BayesianEvent event : this.events) { event.removeAllRelations(); } }
/** * Remove a dependency, if it it exists. * * @param parent The parent event. * @param child The child event. */ private void removeDependency(BayesianEvent parent, BayesianEvent child) { parent.getChildren().remove(child); child.getParents().remove(parent); }