/*
* Encog(tm) Workbench v3.4
* http://www.heatonresearch.com/encog/
* https://github.com/encog/encog-java-workbench
*
* 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.workbench.tabs.bayesian;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import org.encog.Encog;
import org.encog.ml.MLInput;
import org.encog.ml.MLOutput;
import org.encog.ml.MLProperties;
import org.encog.ml.MLResettable;
import org.encog.ml.bayesian.BayesianChoice;
import org.encog.ml.bayesian.BayesianEvent;
import org.encog.ml.bayesian.BayesianNetwork;
import org.encog.ml.bayesian.bif.BIFUtil;
import org.encog.ml.bayesian.table.TableLine;
import org.encog.util.Format;
import org.encog.util.HTMLReport;
import org.encog.workbench.EncogWorkBench;
import org.encog.workbench.dialogs.createnetwork.CreateBayesian;
import org.encog.workbench.frames.MapDataFrame;
import org.encog.workbench.frames.document.EncogDocumentFrame;
import org.encog.workbench.frames.document.tree.ProjectEGFile;
import org.encog.workbench.process.TrainBasicNetwork;
import org.encog.workbench.tabs.EncogCommonTab;
import org.encog.workbench.tabs.visualize.bayesian.BayesianStructureTab;
public class BayesianNetworkTab extends EncogCommonTab implements
ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private JToolBar toolbar;
private JButton buttonRandomize;
private JButton buttonDefineQuery;
private JButton buttonQuery;
private JButton buttonTrain;
private JButton buttonRestructure;
private JButton buttonProperties;
private JButton buttonVisualize;
private JButton buttonImportBIF;
private JButton buttonExportBIF;
private final JScrollPane scroll;
private final JEditorPane editor;
private BayesianNetwork method;
public BayesianNetworkTab(final ProjectEGFile data) {
super(data);
this.method = (BayesianNetwork) data.getObject();
setLayout(new BorderLayout());
this.toolbar = new JToolBar();
this.toolbar.setFloatable(false);
this.toolbar.add(this.buttonRandomize = new JButton("Randomize/Reset"));
this.toolbar.add(this.buttonDefineQuery = new JButton("Define Query"));
this.toolbar.add(this.buttonQuery = new JButton("Query"));
this.toolbar.add(this.buttonTrain = new JButton("Train"));
this.toolbar.add(this.buttonRestructure = new JButton("Restructure"));
this.toolbar.add(this.buttonImportBIF = new JButton("Import BIF"));
this.toolbar.add(this.buttonExportBIF = new JButton("Export BIF"));
this.toolbar.add(this.buttonProperties = new JButton("Properties"));
this.toolbar.add(this.buttonVisualize = new JButton("Visualize"));
this.buttonRandomize.addActionListener(this);
this.buttonQuery.addActionListener(this);
this.buttonDefineQuery.addActionListener(this);
this.buttonTrain.addActionListener(this);
this.buttonRestructure.addActionListener(this);
this.buttonProperties.addActionListener(this);
this.buttonVisualize.addActionListener(this);
this.buttonExportBIF.addActionListener(this);
this.buttonImportBIF.addActionListener(this);
add(this.toolbar, BorderLayout.PAGE_START);
this.editor = new JEditorPane("text/html", "");
this.editor.setEditable(false);
this.scroll = new JScrollPane(this.editor);
add(this.scroll, BorderLayout.CENTER);
produceReport();
}
public void actionPerformed(final ActionEvent action) {
try {
if (action.getSource() == this.buttonQuery) {
performQuery();
} else if (action.getSource() == this.buttonDefineQuery) {
performDefineQuery();
} else if (action.getSource() == this.buttonRandomize) {
performRandomize();
} else if (action.getSource() == this.buttonTrain) {
performTrain();
} else if (action.getSource() == this.buttonRestructure) {
performRestructure();
} else if (action.getSource() == this.buttonProperties) {
performProperties();
} else if (action.getSource() == this.buttonVisualize) {
this.handleVisualize();
} else if (action.getSource() == this.buttonExportBIF) {
this.handleExportBIF();
} else if (action.getSource() == this.buttonImportBIF) {
this.handleImportBIF();
}
} catch (Throwable t) {
EncogWorkBench.displayError("Error", t);
}
}
private void handleExportBIF() {
final JFileChooser fc = new JFileChooser();
if (EncogWorkBench.getInstance().getProjectDirectory() != null)
fc.setCurrentDirectory(EncogWorkBench.getInstance().getProjectDirectory());
fc.addChoosableFileFilter(EncogDocumentFrame.XML_FILTER);
final int result = fc.showSaveDialog(EncogWorkBench.getInstance()
.getMainWindow());
if (result == JFileChooser.APPROVE_OPTION) {
try {
EncogWorkBench.getInstance().getMainWindow().beginWait();
String file = fc.getSelectedFile().getAbsolutePath();
File targetFile = new File(file);
BIFUtil.writeBIF(targetFile, this.method);
EncogWorkBench.getInstance().getMainWindow().redraw();
} catch(Throwable t) {
EncogWorkBench.displayError("Error", t);
} finally {
EncogWorkBench.getInstance().getMainWindow().endWait();
}
}
}
private void handleImportBIF() {
final JFileChooser fc = new JFileChooser();
if (EncogWorkBench.getInstance().getProjectDirectory() != null)
fc.setCurrentDirectory(EncogWorkBench.getInstance()
.getProjectDirectory());
fc.addChoosableFileFilter(EncogDocumentFrame.XML_FILTER);
final int result = fc.showOpenDialog(EncogWorkBench.getInstance()
.getMainWindow());
if (result == JFileChooser.APPROVE_OPTION) {
try {
EncogWorkBench.getInstance().getMainWindow().beginWait();
String file = fc.getSelectedFile().getAbsolutePath();
File sourceFile = new File(file);
this.method = BIFUtil.readBIF(sourceFile);
((ProjectEGFile)this.getEncogObject()).setObject(this.method);
this.produceReport();
this.setDirty(true);
} catch(Throwable t) {
EncogWorkBench.displayError("Error", t);
} finally {
EncogWorkBench.getInstance().getMainWindow().endWait();
}
}
}
private void performTrain() {
TrainBasicNetwork t = new TrainBasicNetwork(
(ProjectEGFile) this.getEncogObject(), this);
t.performTrain();
}
private void performRandomize() {
if (EncogWorkBench.askQuestion("Are you sure?",
"Clear probability tables and lose all training?")) {
if (method instanceof MLResettable) {
((MLResettable) method).reset();
}
produceReport();
EncogWorkBench.getInstance().getMainWindow().redraw();
this.setDirty(true);
}
}
private void performDefineQuery() {
try {
String query = EncogWorkBench.displayInput("Enter query (i.e. P(+x,-y)?", this.method.getQuery().getProblem());
if( query!=null) {
//this.method.defineQuery(query);
EncogWorkBench.displayMessage("Query", "Query successfully updated.");
this.produceReport();
this.setDirty(true);
}
} catch (Throwable t) {
EncogWorkBench.displayError("Error", t);
}
}
private void performQuery() {
boolean success = false;
double p = 0;
try {
EncogWorkBench.getInstance().getMainWindow().beginWait();
this.method.getQuery().execute();
p = this.method.getQuery().getProbability();
success = true;
} catch (Throwable t) {
EncogWorkBench.displayError("Error", t);
} finally {
EncogWorkBench.getInstance().getMainWindow().endWait();
}
EncogWorkBench.getInstance().outputLine(this.method.getQuery().getProblem() + " = " + Format.formatPercent(p));
if( success ) {
EncogWorkBench.displayMessage("Probability", Format.formatPercent(p));
}
}
/**
* @return the data
*/
public BayesianNetwork getData() {
return (BayesianNetwork) this.method;
}
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
public void performProperties() {
if (this.method instanceof MLProperties) {
MapDataFrame frame = new MapDataFrame(
((MLProperties) method).getProperties(), "Properties");
frame.setVisible(true);
setDirty(true);
} else {
EncogWorkBench
.displayError("Error",
"This Machine Learning Method type does not support properties.");
}
}
public void handleVisualize() {
BayesianStructureTab tab = new BayesianStructureTab(this.method);
EncogWorkBench.getInstance().getMainWindow().getTabManager().openModalTab(tab, "Network Structure");
}
public void produceReport() {
HTMLReport report = new HTMLReport();
report.beginHTML();
report.title("MLMethod");
report.beginBody();
report.h1(this.method.getClass().getSimpleName());
report.beginTable();
if (method instanceof MLInput) {
MLInput reg = (MLInput) method;
report.tablePair("Input Count",
Format.formatInteger(reg.getInputCount()));
}
if (method instanceof MLOutput) {
MLOutput reg = (MLOutput) method;
report.tablePair("Output Count",
Format.formatInteger(reg.getOutputCount()));
}
report.tablePair("Parameter Count",
Format.formatInteger(this.method.calculateParameterCount()));
report.tablePair("Expression", this.method.toString());
String queryType = "";
String queryStr = "";
if( method.getQuery()!=null) {
queryType = method.getQuery().getClass().getSimpleName();
queryStr = method.getQuery().getProblem();
}
report.tablePair("Query Type", queryType);
report.tablePair("Query", queryStr);
report.endTable();
report.h3("Events");
report.beginTable();
report.beginRow();
report.header("Event");
report.header("Choices");
report.header("Probability");
report.endRow();
for (BayesianEvent event : this.method.getEvents()) {
report.beginRow();
report.cell(event.getLabel());
StringBuilder l = new StringBuilder();
boolean first = true;
for (BayesianChoice str : event.getChoices()) {
if (!first) {
l.append(", ");
}
first = false;
l.append(str);
}
report.cell(l.toString());
report.cell(event.toString());
report.endRow();
}
report.endTable();
report.h3("Probability Tables");
report.beginTable();
for (BayesianEvent event : this.method.getEvents()) {
report.beginRow();
report.header(event.getLabel(), 2);
report.endRow();
for (TableLine line : event.getTable().getLines()) {
if( line==null )
continue;
report.beginRow();
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;
double arg = line.getArguments()[index];
if (parentEvent.isBoolean()) {
if (Math.abs(arg) < Encog.DEFAULT_DOUBLE_EQUAL) {
str.append("-");
} else {
str.append("+");
}
}
str.append(parentEvent.getLabel());
if (!parentEvent.isBoolean()) {
str.append("=");
str.append(arg);
}
}
str.append(")");
report.cell(str.toString());
report.cell(Format.formatPercent(line.getProbability()));
report.endRow();
}
}
report.endTable();
report.endBody();
report.endHTML();
this.editor.setText(report.toString());
}
private void performRestructure() {
String priorQuery = this.method.getQuery().getProblem();
String priorContents = this.method.getContents();
CreateBayesian d = new CreateBayesian(this.method);
d.getQuery().setValue(priorQuery);
d.getContents().setValue(priorContents);
if( d.process() ) {
String currentQuery = d.getQuery().getValue();
String currentContents = d.getContents().getValue();
boolean changed = false;
if( !priorQuery.equals(currentQuery)) {
//this.method.defineQuery(currentQuery);
changed = true;
}
if( !priorContents.equals(currentContents)) {
this.method.setContents(currentContents);
changed = true;
}
if( changed ) {
produceReport();
EncogWorkBench.getInstance().getMainWindow().redraw();
this.setDirty(true);
}
}
}
@Override
public String getName() {
return this.getEncogObject().getName();
}
}