/** * BayesNet.java * @author Fabio G. Cozman * Copyright 1996 - 1999, Fabio G. Cozman, * Carnergie Mellon University, Universidade de Sao Paulo * fgcozman@usp.br, http://www.cs.cmu.edu/~fgcozman/home.html * * The JavaBayes distribution is free software; you can * redistribute it and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation (either * version 2 of the License or, at your option, any later version), * provided that this notice and the name of the author appear in all * copies. Upon request to the author, some of the packages in the * JavaBayes distribution can be licensed under the GNU Lesser General * Public License as published by the Free Software Foundation (either * version 2 of the License, or (at your option) any later version). * If you're using the software, please notify fgcozman@usp.br so * that you can receive updates and patches. JavaBayes is distributed * "as is", in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with the JavaBayes distribution. If not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package BayesianNetworks; import InterchangeFormat.*; import java.io.*; import java.net.URL; import java.util.Vector; import java.util.Enumeration; import java.util.Date; /* ************************************************************************ */ public class BayesNet { protected String name; protected Vector properties; protected ProbabilityVariable probability_variables[]; protected ProbabilityFunction probability_functions[]; protected DiscreteFunction utility_function; public final static int INVALID_INDEX = -1; public final static int BIF = 1; public final static int XML = 2; public final static int BUGS = 3; /** * Default constructor for a BayesNet. */ public BayesNet() { } /** * Simple constructor for a BayesNet. * @param n_n Name of the network. * @param n_v Number of variables in the network. * @param n_f Number of probability distributions in the network. */ public BayesNet(String n_n, int n_v, int n_f) { this(); name = n_n; probability_variables = new ProbabilityVariable[n_v]; probability_functions = new ProbabilityFunction[n_f]; } /** * Simple constructor for a BayesNet. * @param n_n Name of network. * @param p Properties of the network. */ public BayesNet(String n_n, Vector p) { this(); name = n_n; properties = p; } /** * Simple constructor for a BayesNet; creates a copy of a given * network. * @param bn Network to be copied. */ public BayesNet(BayesNet bn) { this(bn.name, bn.probability_variables.length, bn.probability_functions.length); for (int i=0; i<bn.probability_variables.length; i++) probability_variables[i] = bn.probability_variables[i]; for (int i=0; i<bn.probability_functions.length; i++) probability_functions[i] = bn.probability_functions[i]; properties = bn.properties; } /** * Construct a BayesNet from a textual description in a string. */ public BayesNet(String s) throws IFException { this(); StringBufferInputStream istream = new StringBufferInputStream(s); // Read the BayesNet from the stream InterchangeFormat ifo = new InterchangeFormat(istream); ifo.CompilationUnit(); // Transfer information from the parser translate(ifo); } /** * Construct a BayesNet from a textual description in a stream. */ public BayesNet(InputStream istream) throws IFException { this(); // Read the BayesNet from the stream InterchangeFormat ifo = new InterchangeFormat(istream); ifo.CompilationUnit(); // Now transfer information from the parser translate(ifo); } /** * Construct a BayesNet from a textual description * in an URL. * @param context The URL context as defined in the Java libraries. * @param spec The URL spec as defined in the Java libraries. */ public BayesNet(URL context, String spec) throws IFException, IOException { this(); URL url = new URL(context, spec); InputStream istream = url.openStream(); // Read the BayesNet from the stream InterchangeFormat ifo = new InterchangeFormat(istream); ifo.CompilationUnit(); // Now transfer information from the parser translate(ifo); istream.close(); } /** * Construct a BayesNet from a textual description in an URL. */ public BayesNet(URL url) throws IFException, IOException { this(); InputStream istream = url.openStream(); // Read the BayesNet from the stream InterchangeFormat ifo = new InterchangeFormat(istream); ifo.CompilationUnit(); // Now transfer information from the parser translate(ifo); istream.close(); } /* * Translate the contents of a * IFBayesNet object into a BayesNet object. * * This method makes modifications to the basic objects * supported by the InterchangeFormat, so that the full * functionality of the BayesianNetworks package can be used. * As the InterchangeFormat evolves, probably some of the * objects created through extensions will be created directly * by the parser as it parses an InterchangeFormat stream. * Right now the extensions involve: * 1) Detecting observed variables. * 2) Detecting explanation variables. */ protected void translate(InterchangeFormat ifo) { ConvertInterchangeFormat cbn = new ConvertInterchangeFormat(ifo); name = cbn.get_name(); properties = cbn.get_properties(); probability_variables = cbn.get_probability_variables(this); probability_functions = cbn.get_probability_functions(this); // Process BayesNet properties process_properties(); // Process ProbabilityVariable properties for (int i=0; i<probability_variables.length; i++) process_probability_variable_properties(i); // Process ProbabilityFunction properties for (int i=0; i<probability_functions.length; i++) process_probability_function_properties(i); } /* * Make modifications to a BayesNet based on the properties of * the BayesNet. */ protected void process_properties() { } /* * Process the properties of a ProbabilityVariable. */ protected void process_probability_variable_properties(int index) { probability_variables[index].process_properties(); } /* * Process the properties of a ProbabilityFunction. */ protected void process_probability_function_properties(int index) { probability_functions[index].process_properties(); } /** * Find the ProbabilityFunction that corresponds to a * given ProbabilityVariable. * Note: the index of a variable is used by the function, as it * is the only reference to the variable that is guaranteed to identify * the variable uniquely. */ public ProbabilityFunction get_function(ProbabilityVariable p_v) { for (int i=0; i<probability_functions.length; i++) if (p_v.index == probability_functions[i].variables[0].index) return(probability_functions[i]); return(null); } /** * Save a BayesNet object in a stream, in the BIF InterchangeFormat. */ public void save_bif(PrintStream out) { int i; String property; out.println("// Bayesian network "); if (name != null) out.print("network \"" + name + "\" {"); if (probability_variables != null) out.print(" //" + probability_variables.length + " variables"); if (probability_functions != null) out.print(" and " + probability_functions.length + " probability distributions"); out.println(); if ((properties != null) && (properties.size() > 0)) { for (Enumeration e = properties.elements(); e.hasMoreElements(); ) { property = (String)(e.nextElement()); out.println("\tproperty \"" + property + "\" ;"); } } out.println("}"); if (probability_variables != null) for (i=0; i<probability_variables.length; i++) if (probability_variables[i] != null) probability_variables[i].print(out); if (probability_functions != null) for (i=0; i<probability_functions.length; i++) if (probability_functions[i] != null) probability_functions[i].print(out); } /** * Save a BayesNet object in a stream for the EBayes engine. */ public void save_embayes(PrintStream out) { int i, j; out.println("import ebayes.data.*"); out.println("class " + name + " extends BayesNet {"); out.println("\tpublic " + name + "() {"); out.println("\tsetName(\"" + name + "\");"); for (i=0; i<probability_variables.length; i++) { out.println("\tCategoricalVariable " + probability_variables[i].name + " = "); out.println("\t\tnew CategoricalVariable(\"" + probability_variables[i].name + "\","); out.print("\t\t\tnew String[] {"); for (j=0; j<probability_variables[i].values.length; j++) { out.print("\"" + probability_variables[i].values[j] + "\""); if (j != (probability_variables[i].values.length - 1)) out.print(","); } out.println("});\n"); } out.println("\n\n"); for (i=0; i<probability_functions.length; i++) { out.println("\tCategoricalProbability p" + i + " = "); out.println("\t\tnew CategoricalProbability(" + probability_functions[i].variables[0].get_name() + ","); if (probability_functions[i].variables.length > 1) { out.print("\t\t\tnew CategoricalVariable[] {"); for (j=1; j<probability_functions[i].variables.length; j++) { out.print(probability_functions[i].variables[j].get_name()); if (j != (probability_functions[i].variables.length - 1)) out.print(", "); } out.println("}, "); } out.print("\t\t\tnew double[] {"); for (j=0; j<probability_functions[i].values.length; j++) { out.print(probability_functions[i].values[j]); if (j != (probability_functions[i].values.length - 1)) out.print(", "); } out.println("});\n"); } out.println("\tsetVariables("); out.println("\t\tnew CategoricalVariable[]"); out.print("\t\t\t{"); for (i=0; i<probability_variables.length; i++) { out.print(probability_variables[i].get_name()); if (i != (probability_variables.length - 1)) out.print(", "); } out.println("} );\n"); out.println("\tsetProbabilities("); out.println("\t\tnew CategoricalProbability[]"); out.print("\t\t\t{"); for (i=0; i<probability_functions.length; i++) { out.print("p" + i); if (i != (probability_functions.length - 1)) out.print(", "); } out.println("} );\n"); out.println("\n}"); } /** * Save a BayesNet object in a stream, in the XMLBIF format * version 0.3 (most recent version). */ public void save_xml(PrintStream pstream) { int i; String property; // Heading for the file pstream.println("<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n\n"); pstream.println("<!--"); pstream.println("\tBayesian network in XMLBIF v0.3 (BayesNet Interchange Format)"); pstream.println("\tProduced by JavaBayes (http://www.cs.cmu.edu/~javabayes/"); pstream.println("\tOutput created " + (new Date())); pstream.println("-->\n\n\n"); pstream.println("<!-- DTD for the XMLBIF 0.3 format -->"); pstream.println("<!DOCTYPE BIF [\n" + "\t<!ELEMENT BIF ( NETWORK )*>\n" + "\t <!ATTLIST BIF VERSION CDATA #REQUIRED>\n" + "\t<!ELEMENT NETWORK ( NAME, ( PROPERTY | VARIABLE | DEFINITION )* )>\n" + "\t<!ELEMENT NAME (#PCDATA)>\n" + "\t<!ELEMENT VARIABLE ( NAME, ( OUTCOME | PROPERTY )* ) >\n" + "\t <!ATTLIST VARIABLE TYPE (nature|decision|utility) \"nature\">\n" + "\t<!ELEMENT OUTCOME (#PCDATA)>\n" + "\t<!ELEMENT DEFINITION ( FOR | GIVEN | TABLE | PROPERTY )* >\n" + "\t<!ELEMENT FOR (#PCDATA)>\n" + "\t<!ELEMENT GIVEN (#PCDATA)>\n" + "\t<!ELEMENT TABLE (#PCDATA)>\n" + "\t<!ELEMENT PROPERTY (#PCDATA)>\n" + "]>\n\n"); // Start of Bayes net pstream.println("<BIF VERSION=\"0.3\">"); // Bayes net description pstream.println("<NETWORK>"); if (name != null) pstream.println("<NAME>" + name + "</NAME>"); if ((properties != null) && (properties.size() > 0)) { for (Enumeration e = properties.elements(); e.hasMoreElements(); ) { property = (String)(e.nextElement()); pstream.println("\t<PROPERTY>" + property + "</PROPERTY>"); } } pstream.println(); // Variables pstream.println("<!-- Variables -->"); if (probability_variables != null) for (i=0; i<probability_variables.length; i++) if (probability_variables[i] != null) probability_variables[i].save_xml_0_3(pstream); pstream.println(); // Probability distributions. pstream.println("<!-- Probability distributions -->"); if (probability_functions != null) for (i=0; i<probability_functions.length; i++) if (probability_functions[i] != null) probability_functions[i].save_xml_0_3(pstream); pstream.println(); // End of Bayes net description. pstream.println("</NETWORK>"); // End of Bayes net. pstream.println("</BIF>"); } /** * Save a BayesNet object in a stream, in the XMLBIF format * version 0.2. */ public void save_xml_0_2(PrintStream pstream) { int i; String property; // Heading for the file pstream.println("<?XML VERSION=\"1.0\"?>\n\n"); pstream.println("<!--"); pstream.println("\tBayesian network in BIF (BayesNet Interchange Format)"); pstream.println("\tProduced by JavaBayes (http://www.cs.cmu.edu/~javabayes/"); pstream.println("\tOutput created " + (new Date())); pstream.println("-->\n\n\n"); pstream.println("<!-- DTD for the BIF format -->"); pstream.println("<!DOCTYPE BIF [\n" + "\t<!ELEMENT BIF ( NETWORK )*>\n" + "\t<!ELEMENT PROPERTY (#PCDATA)>\n" + "\t<!ELEMENT TYPE (#PCDATA)>\n" + "\t<!ELEMENT VALUE (#PCDATA)>\n" + "\t<!ELEMENT NAME (#PCDATA)>\n" + "\t<!ELEMENT NETWORK\n" + "\t ( NAME, ( PROPERTY | VARIABLE | PROBABILITY )* )>\n" + "\t<!ELEMENT VARIABLE ( NAME, TYPE, ( VALUE | PROPERTY )* ) >\n" + "\t<!ELEMENT PROBABILITY\n" + "\t ( FOR | GIVEN | TABLE | ENTRY | DEFAULT | PROPERTY )* >\n" + "\t<!ELEMENT FOR (#PCDATA)>\n" + "\t<!ELEMENT GIVEN (#PCDATA)>\n" + "\t<!ELEMENT TABLE (#PCDATA)>\n" + "\t<!ELEMENT DEFAULT (TABLE)>\n" + "\t<!ELEMENT ENTRY ( VALUE* , TABLE )>\n" + "]>\n\n"); // Start of Bayes net pstream.println("<BIF>"); // Bayes net description pstream.println("<NETWORK>"); if (name != null) pstream.println("<NAME>" + name + "</NAME>"); if ((properties != null) && (properties.size() > 0)) { for (Enumeration e = properties.elements(); e.hasMoreElements(); ) { property = (String)(e.nextElement()); pstream.println("\t<PROPERTY>" + property + "</PROPERTY>"); } } pstream.println(); // Variables pstream.println("<!-- Variables -->"); if (probability_variables != null) for (i=0; i<probability_variables.length; i++) if (probability_variables[i] != null) probability_variables[i].save_xml(pstream); pstream.println(); // Probability distributions. pstream.println("<!-- Probability distributions -->"); if (probability_functions != null) for (i=0; i<probability_functions.length; i++) if (probability_functions[i] != null) probability_functions[i].save_xml(pstream); pstream.println(); // End of Bayes net description. pstream.println("</NETWORK>"); // End of Bayes net. pstream.println("</BIF>"); } /** * Save a BayesNet object into a stream, in the BUGS format. */ public void save_bugs(PrintStream pstream) { SaveBugs sb = new SaveBugs(this); sb.save(pstream); } /** * Get all the evidence contained in the network variables. */ public String[][] get_all_evidence() { int i, j, aux; ProbabilityVariable pv; Vector evs = new Vector(); Enumeration e; String all_evs[][] = null; for (i=0; i<probability_variables.length; i++) { pv = probability_variables[i]; if (pv.observed_index != BayesNet.INVALID_INDEX) evs.addElement(pv); } all_evs = new String[ evs.size() ][]; for (i=0; i<all_evs.length; i++) all_evs[i] = new String[2]; j = 0; for (e = evs.elements(); e.hasMoreElements(); ) { pv = (ProbabilityVariable)(e.nextElement()); all_evs[j][0] = pv.name; aux = pv.observed_index; all_evs[j][1] = pv.values[aux]; } return(all_evs); } /** * Determine the position of a variable given its name. */ public int index_of_variable(String n_vb) { int i; for (i=0; i<probability_variables.length; i++) { if (probability_variables[i].name.equals(n_vb)) return(i); } return(-1); // Returns -1 if name is not valid! } /** * Print a BayesNet in the standard output. */ public void print() { print(System.out); } /** * Print a BayesNet in a given stream. */ public void print(PrintStream out) { save_bif(out); } /* *************************************************************** * * Methods that allow basic manipulation of non-public variables * * *************************************************************** */ /** * Get the name of the network. */ public String get_name() { return(name); } /** * Set the name of the network. */ public void set_name(String n) { name = n; } /** * Get the properties. */ public Vector get_properties() { return(properties); } /** * Set the properties. */ public void set_properties(Vector prop) { properties = prop; } /** * Add a property. */ public void add_property(String prop) { if (properties == null) properties = new Vector(); properties.addElement(prop); } /** * Remove a property. */ public void remove_property(String prop) { properties.removeElement(prop); } /** * Remove a property. */ public void remove_property(int i) { properties.removeElementAt(i); } /** * Get the number of variables in the network. */ public int number_variables() { if (probability_variables == null) return(BayesNet.INVALID_INDEX); return(probability_variables.length); } /** * Get the number of distributions in the network. */ public int number_probability_functions() { if (probability_functions == null) return(BayesNet.INVALID_INDEX); return(probability_functions.length); } /** * Get the probability variable at a given index. */ public ProbabilityVariable get_probability_variable(int index) { if (index <= probability_variables.length) return(probability_variables[index]); else return(null); } /** * Get the probability function at a given index. */ public ProbabilityFunction get_probability_function(int index) { if (index <= probability_functions.length) return(probability_functions[index]); else return(null); } /** * Get the probability variables. */ public ProbabilityVariable[] get_probability_variables() { return(probability_variables); } /** * Get the probability functions. */ public ProbabilityFunction[] get_probability_functions() { return(probability_functions); } /** * Get the utility function. */ public DiscreteFunction get_utility_function() { return(utility_function); } /** * Set a probability variable given its constituents. */ public void set_probability_variable(int index, String name, String v[], Vector vec) { if (index <= probability_variables.length) { probability_variables[index] = new ProbabilityVariable(this, name, index, v, vec); } } /** * Set a probability function given its constituents. */ public void set_probability_function(int index, ProbabilityVariable[] variables, double values[], Vector vec) { if (index <= probability_functions.length) { probability_functions[index] = new ProbabilityFunction(this, variables, values, vec); } } /** * Set a probability variable given its index. */ public void set_probability_variable(int index, ProbabilityVariable p_v) { p_v.bn = this; p_v.index = index; probability_variables[index] = p_v; } /** * Set a probability variable given its index. */ public void set_probability_function(int index, ProbabilityFunction p_f) { p_f.bn = this; probability_functions[index] = p_f; } /** * Set the vector of probability variables. */ public void set_probability_variables(ProbabilityVariable pvs[]) { probability_variables = pvs; } /** * Set the vector of probability functions. */ public void set_probability_functions(ProbabilityFunction pfs[]) { probability_functions = pfs; } }