/*
* Encog(tm) Core v3.4 - Java Version
* http://www.heatonresearch.com/encog/
* https://github.com/encog/encog-java-core
* Copyright 2008-2016 Heaton Research, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For more information on Heaton Research copyrights, licenses
* and trademarks visit:
* http://www.heatonresearch.com/copyright
*/
package org.encog.ml.bayesian.bif;
import java.util.ArrayList;
import java.util.List;
import org.encog.ml.bayesian.BayesianChoice;
import org.encog.ml.bayesian.BayesianEvent;
import org.encog.ml.bayesian.BayesianNetwork;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Handler, used to parse the XML BIF files.
*/
public class BIFHandler extends DefaultHandler {
/**
* The current section.
*/
private final List<FileSection> currentSection = new ArrayList<FileSection>();
/**
* BIF variables.
*/
private final List<BIFVariable> bifVariables = new ArrayList<BIFVariable>();
/**
* BIF definitions.
*/
private final List<BIFDefinition> bifDefinitions = new ArrayList<BIFDefinition>();
/**
* The current variable.
*/
private BIFVariable currentVariable;
/**
* The current definition.
*/
private BIFDefinition currentDefinition;
/**
* THe current string.
*/
private String currentString;
/**
* The network bing loaded.
*/
private BayesianNetwork network;
/**
* Constructor.
*/
public BIFHandler() {
this.network = new BayesianNetwork();
}
/**
* Handle the beginning of the BIF tag.
* @param qName The name of the tag.
* @param attributes The attributes.
*/
private void handleBeginBIF(String qName, Attributes attributes) {
if (qName.equals("NETWORK")) {
this.currentSection.add(FileSection.NETWORK);
}
}
/**
* Handle the beginning of the BIF tag.
* @param qName The name of the tag.
* @param attributes The attributes.
*/
private void handleBeginNETWORK(String qName, Attributes attributes) {
if (qName.equals("VARIABLE")) {
this.currentSection.add(FileSection.VARIABLE);
this.currentVariable = new BIFVariable();
this.bifVariables.add(this.currentVariable);
} else if (qName.equals("DEFINITION")) {
this.currentSection.add(FileSection.DEFINITION);
this.currentDefinition = new BIFDefinition();
this.bifDefinitions.add(this.currentDefinition);
}
}
/**
* Handle the beginning of the BIF tag.
* @param qName The name of the tag.
* @param attributes The attributes.
*/
private void handleBeginVARIABLE(String qName, Attributes attributes) {
if (qName.equals("VARIABLE")) {
this.currentVariable = new BIFVariable();
this.bifVariables.add(this.currentVariable);
}
}
/**
* Handle the beginning of the DEFINITION tag.
* @param qName The name of the tag.
*/
private void handleBeginDEFINITION(String qName, Attributes attributes) {
if (qName.equals("DEFINITION")) {
this.currentDefinition = new BIFDefinition();
this.bifDefinitions.add(this.currentDefinition);
}
}
/**
* Handle the end of the BIF tag.
* @param qName The name of the tag.
*/
private void handleEndBIF(String qName) {
if (qName.equals("BIF")) {
this.currentSection.remove(this.currentSection.size() - 1);
}
}
/**
* Handle the end of the NETWORK tag.
* @param qName The name of the tag.
*/
private void handleEndNETWORK(String qName) {
if (qName.equals("NETWORK")) {
this.currentSection.remove(this.currentSection.size() - 1);
}
}
/**
* Handle the end of the VARIABLE tag.
* @param qName The name of the tag.
*/
private void handleEndVARIABLE(String qName) {
if (qName.equals("NAME")) {
this.currentVariable.setName(this.currentString);
} else if (qName.equals("OUTCOME")) {
this.currentVariable.addOption(this.currentString);
} else if( qName.equals("VARIABLE") ) {
this.currentSection.remove(this.currentSection.size() - 1);
}
}
/**
* Handle the end of the DEFINITION tag.
* @param qName The name of the tag.
*/
private void handleEndDEFINITION(String qName) {
if (qName.equals("FOR")) {
this.currentDefinition.setForDefinition(this.currentString);
} else if (qName.equals("GIVEN")) {
this.currentDefinition.addGiven(this.currentString);
} else if (qName.equals("TABLE")) {
this.currentDefinition.setTable(this.currentString);
} else if( qName.equals("DEFINITION") ) {
this.currentSection.remove(this.currentSection.size() - 1);
}
}
/**
* {@inheritDoc}
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if (this.currentSection.size() == 0 && qName.equals("BIF")) {
this.currentSection.add(FileSection.BIF);
}
else if (this.currentSection.size() > 0) {
switch (this.currentSection.get(this.currentSection.size() - 1)) {
case BIF:
handleBeginBIF(qName, attributes);
break;
case DEFINITION:
handleBeginDEFINITION(qName, attributes);
break;
case NETWORK:
handleBeginNETWORK(qName, attributes);
break;
case VARIABLE:
handleBeginVARIABLE(qName, attributes);
break;
}
}
}
/**
* @return The network being parsed.
*/
public BayesianNetwork getNetwork() {
return network;
}
/**
* {@inheritDoc}
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
if (this.currentSection.size() > 0) {
switch (this.currentSection.get(this.currentSection.size() - 1)) {
case BIF:
handleEndBIF(qName);
break;
case DEFINITION:
handleEndDEFINITION(qName);
break;
case NETWORK:
handleEndNETWORK(qName);
break;
case VARIABLE:
handleEndVARIABLE(qName);
break;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void endDocument() throws SAXException {
super.endDocument();
// define variables
for (BIFVariable v : this.bifVariables) {
List<BayesianChoice> c = new ArrayList<BayesianChoice>();
int index = 0;
for(String s : v.getOptions() ) {
c.add(new BayesianChoice(s,index++));
}
this.network.createEvent(v.getName(), c);
}
// define relations
for (BIFDefinition d : this.bifDefinitions) {
BayesianEvent childEvent = this.network.requireEvent(d
.getForDefinition());
for (String s : d.getGivenDefinitions()) {
BayesianEvent parentEvent = this.network.requireEvent(s);
this.network.createDependency(parentEvent, childEvent);
}
}
this.network.finalizeStructure();
// define probabilities
for (BIFDefinition d : this.bifDefinitions) {
double[] t = d.getTable();
BayesianEvent childEvent = this.network.requireEvent(d.getForDefinition());
int tableIndex = 0;
int[] args = new int[childEvent.getParents().size()];
do {
for(int result = 0; result<childEvent.getChoices().size();result++) {
childEvent.getTable().addLine(t[tableIndex++], result, args);
}
} while(BIFUtil.rollArgs(childEvent,args));
}
}
/**
* {@inheritDoc}
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
this.currentString = new String(ch, start, length);
}
}