/**
* DiscreteFunction.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 java.io.PrintStream;
import java.util.Vector;
import java.util.Enumeration;
/* ***************************************************************** */
public class DiscreteFunction {
protected DiscreteVariable variables[];
protected double values[];
/**
* Default constructor for a DiscreteFunction.
*/
public DiscreteFunction() {
}
/**
* Simple constructor for DiscreteFunction.
* @param n_vb Number of variables in the function.
* @param n_vl Number of values in the function.
*/
public DiscreteFunction(int n_vb, int n_vl) {
variables = new DiscreteVariable[n_vb];
values = new double[n_vl];
}
/**
* Simple constructor for DiscreteFunction.
* @param pvs An array of ProbabilityVariable objects.
* @param v An array of values for the function.
*/
public DiscreteFunction(DiscreteVariable pvs[], double v[]) {
variables = pvs;
values = v;
}
/**
* Check whether an index is present in the function.
*/
public boolean memberOf(int index) {
for (int i=0; i<variables.length; i++) {
if (index == variables[i].index) return(true);
}
return(false);
}
/*
* Method that determines whether a DiscreteFunction
* contain some DiscreteVariable in common with the current DiscreteFunction.
* @param df DiscreteFunction to be compared with the current DiscreteFunction.
*/
boolean same_variables(DiscreteFunction df) {
if (variables.length != df.variables.length) return(false);
for (int i=0; i<variables.length; i++) {
if (variables[i] != df.variables[i]) return(false);
}
return(true);
}
/**
* Evaluate a function given a (possibly partial) instantiation of
* variables through the indexes. Indexes indicate which variables
* are present in the function to be evaluated, assuming an array of
* DiscreteVariable objects is present.
* @param pvs The array of DiscreteVariable objects that is used to
* compute the position indicated by the markers.
* @param value_indexes The markers.
*/
public double evaluate(DiscreteVariable pvs[], int value_indexes[]) {
int position = get_position_from_indexes(pvs, value_indexes);
return(values[position]);
}
/**
* Get position in a function from a (possibly
* partial) instantiation of variables through the indexes.
*/
public int get_position_from_indexes(DiscreteVariable pvs[],
int variable_indexes[]) {
int k, pos = 0, jump = 1;
for (int i=(variables.length-1); i>=0; i--) {
k = variables[i].index;
pos += variable_indexes[k] * jump;
jump *= pvs[k].values.length;
}
return(pos);
}
/**
* Sum out some variables in the function.
* @param markers A boolean vector indicating which variables are
* to be summed out. If markers[i] is true, then the
* ith variable is to be summed out; if markers[i] is
* false, the ith variable is not to be summed out.
*/
public DiscreteFunction sum_out(DiscreteVariable dvs[], boolean markers[]) {
int i, j, k, current;
double t, v;
// Initialize the indexes and the maximum length for all ProbabilityVariable objects.
// This is used to circle through all the values in the new_df.
int indexes[] = new int[dvs.length];
int value_lengths[] = new int[dvs.length];
for (i=0; i<dvs.length; i++) {
indexes[i] = 0;
value_lengths[i] = dvs[i].number_values();
}
// Collect some information used to construct the new_df.
int number_of_variables_to_sum_out = 0;
int number_of_variables_to_stay = 0;
int number_of_values_new_df = 1;
int number_of_values_to_sum_out = 1;
for (i=0; i<variables.length; i++) {
if (markers[ variables[i].get_index() ] == true) {
number_of_variables_to_sum_out++;
number_of_values_to_sum_out *= variables[i].number_values();
}
else {
number_of_variables_to_stay++;
number_of_values_new_df *= variables[i].number_values();
}
}
// If there is no variable that must stay, then return null.
if (number_of_variables_to_stay == 0) return(null);
// If there is no variable to sum out, then return copy.
if (number_of_variables_to_sum_out == 0)
return( new DiscreteFunction(variables, values) );
// Initialize a vector with the indexes of variables to sum out.
int index_for_variables_to_sum_out[] = new int[number_of_variables_to_sum_out];
// Build the new_df and the indexes of variables to sum out.
DiscreteFunction new_df =
new DiscreteFunction(number_of_variables_to_stay, number_of_values_new_df);
for (i=0, j=0, k=0; i<variables.length; i++) {
if (markers[ variables[i].get_index() ] == true) { // Fill in the index of variables to sum out.
index_for_variables_to_sum_out[k] = variables[i].get_index();
k++;
}
else { // Fill in the variables in the new_df.
new_df.set_variable(j, variables[i]);
j++;
}
}
// Store the last valid indexes (efficiency purposes only).
int last_new_df = new_df.number_variables() - 1;
int last_index_for_variables_to_sum_out = index_for_variables_to_sum_out.length - 1;
// Now circle through all the values, doing the summation.
for (i=0; i<new_df.number_values(); i++) { // Go through all values of the new_df.
v = 0.0;
// Reset the indexes for the values to sum out.
for (j=0; j<index_for_variables_to_sum_out.length; j++)
indexes[ index_for_variables_to_sum_out[j] ] = 0;
// Do the summation for a value.
for (j=0; j<number_of_values_to_sum_out; j++) { // Go through all values to be summed out.
v += evaluate(dvs, indexes); // Do the summation for each value of the new_df.
// Increment the last index to be summed out.
indexes[ index_for_variables_to_sum_out[last_index_for_variables_to_sum_out] ]++;
for (k=last_index_for_variables_to_sum_out; k>0; k--) { // Now do the updating of all indexes.
current = index_for_variables_to_sum_out[k];
if (indexes[current] >= value_lengths[current]) { // If overflow in an index,
indexes[current] = 0;
indexes[ index_for_variables_to_sum_out[k - 1] ]++; // then update the next index.
}
else
break;
}
}
// Insert the summation for the value of new_df into new_df.
new_df.set_value(i, v);
// Update the indexes.
indexes[ new_df.get_index(last_new_df) ]++; // Increment the last index.
for (j=last_new_df; j>0; j--) { // Now do the updating of all indexes.
current = new_df.get_index(j);
if (indexes[current] >= value_lengths[current]) { // If overflow in an index,
indexes[current] = 0;
indexes[ new_df.get_index(j - 1) ]++; // then update the next index.
}
else
break;
}
}
return(new_df);
}
/**
* Multiply two DiscreteFunction objects.
*/
public DiscreteFunction multiply(DiscreteVariable dvs[], DiscreteFunction mult) {
int i, j, k, n, v, current, joined_indexes[];
double t;
boolean variable_markers[] = new boolean[dvs.length];
// This is used to circle through all the values in the new_df.
int indexes[] = new int[dvs.length];
int value_lengths[] = new int[dvs.length];
for (i=0; i<dvs.length; i++) {
indexes[i] = 0;
value_lengths[i] = dvs[i].number_values();
variable_markers[i] = false;
}
// Join the indexes of this and mult.
n = 0;
for (j=0; j<this.number_variables(); j++) {
k = this.get_index(j);
if (variable_markers[k] == false) {
variable_markers[k] = true;
n++;
}
}
for (j=0; j<mult.number_variables(); j++) {
k = mult.get_index(j);
if (variable_markers[k] == false) {
variable_markers[k] = true;
n++;
}
}
// Calculate necessary quantities
joined_indexes = new int[n];
j=0; v=1;
for (i=0; i<variable_markers.length; i++) {
if (variable_markers[i] == true) {
joined_indexes[j] = i;
j++;
v *= dvs[i].number_values();
}
}
// Create new function to be filled with joined variables
DiscreteFunction new_df = new DiscreteFunction(n, v);
for (i=0; i<n; i++) {
new_df.set_variable(i, dvs[ joined_indexes[i] ]);
}
// Store the last valid indexes (efficiency purposes only).
int last_new_df = new_df.number_variables() - 1;
// Now circle through all the values, doing the multiplication.
for (i=0; i<new_df.number_values(); i++) { // Go through all values of the new_df.
t = this.evaluate(dvs, indexes) * mult.evaluate(dvs, indexes);
// Insert the summation for the value of new_df into new_df.
new_df.set_value(i, t);
// Update the indexes.
indexes[ new_df.get_index(last_new_df) ]++; // Increment the last index.
for (j=last_new_df; j>0; j--) { // Now do the updating of all indexes.
current = new_df.get_index(j);
if (indexes[current] >= value_lengths[current]) { // If overflow in an index,
indexes[current] = 0;
indexes[ new_df.get_index(j - 1) ]++; // then update the next index.
}
else
break;
}
}
return(new_df);
}
/**
* Normalize a function (in-place).
*/
public void normalize() {
int i;
double total = 0.0;
for (i=0; i<values.length; i++)
total += values[i];
if (total>0.0) {
for (i=0; i<values.length; i++)
values[i] = values[i]/total;
}
}
/**
* Normalize a function (in-place)
* assuming that it is a conditional distribution for the
* first variable
*/
public void normalize_first() {
int i, j;
int jump = 1;
double n;
for (i=1; i<variables.length; i++)
jump *= variables[i].values.length;
for (i=0; i<jump; i++) {
n = 0.0;
for (j=0; j<variables[0].values.length; j++)
n += values[ i + j*jump ];
if (n>0.0) {
for (j=0; j<variables[0].values.length; j++)
values[ i + j * jump ] = values[ i + j*jump ]/n;
}
}
}
/**
* Print method for DiscreteFunction.
*/
public void print() {
print(System.out);
}
/**
* Print method for DiscreteFunction into a PrintStream.
*/
public void print(PrintStream out) {
int j;
if (variables != null) {
out.print("discrete function ( ");
for (j=0; j<variables.length; j++)
out.print(" \"" + variables[j].name + "\" ");
out.print(") {");
out.println(" //" + variables.length +
" variable(s) and " + values.length + " values");
out.print("\ttable ");
for (j=0; j<values.length; j++)
out.print(values[j] + " ");
out.print(";");
}
out.println();
out.println("}");
}
/* *************************************************************** */
/* Methods that allow basic manipulation of non-public variables. */
/* *************************************************************** */
/**
* Return the number of DiscreteVariable objects in the current DiscreteFunction.
*/
public int number_variables() {
return(variables.length);
}
/**
* Return the number of values in the current DiscreteFunction.
*/
public int number_values() {
return(values.length);
}
/**
* Get the variables in the current DiscreteFunction.
*/
public DiscreteVariable[] get_variables() {
return(variables);
}
/**
* Get a variable in the current DiscreteFunction.
* @param index Position of the variable to be returned
* in the array of DiscreteVariable objects.
*/
public DiscreteVariable get_variable(int index) {
return(variables[index]);
}
/**
* Get an array with all the indexes of the DiscreteVariable
* objects in the current DiscreteFunction.
*/
public int[] get_indexes() {
int ind[] = new int[variables.length];
for (int i=0; i<ind.length; i++)
ind[i] = variables[i].index;
return(ind);
}
/**
* Get a DiscreteVariable object with a particular index.
* @param ind Index of the desired DiscreteVariable.
*/
public int get_index(int ind) {
return(variables[ind].index);
}
/**
* Get all values of the current DiscreteFunction.
*/
public double[] get_values() {
return(values);
}
/**
* Get a value of the current DiscreteFunction given the position
* of the value in the array of values.
*/
public double get_value(int index) {
return(values[index]);
}
/**
* Set a value in the current DiscreteFunction given its
* position in the array of values.
* @param index The position of the value.
* @param v The new value.
*/
public void set_value(int index, double v) {
values[index] = v;
}
/**
* Set the values in the DiscreteFunction.
*/
public void set_values(double vs[]) {
values = vs;
}
/**
* Set a DiscreteVariable in the current DiscreteFunction given its
* position in the array of values.
* @param index The position of the value.
* @param pv The new DiscreteVariable.
*/
public void set_variable(int index, DiscreteVariable dv) {
variables[index] = dv;
}
}