forum.hugin.com

User Forums => HUGIN API Discussion => Java => Topic started by: jack on July 20, 2011, 17:46:33

Title: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on July 20, 2011, 17:46:33
Hi,
can anybody please tell me how to pass database for EM learning using JAVA HUGIN API.
I realized that you should do with the method learnTable () of the class domain ,
but I haven't understand how to pass to the method my database (MySQL).

Please help!
Thanks
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Martin on July 22, 2011, 11:16:09
There is no direct method for inserting cases from a mysql database.

What you have to do is to write some code that first creates the cases in the Domain from your mysql data, and then invokes the learnTables method.

In code you will have to iterate each case in your mysql database, and use HUGIN API methods for creating the case in the Domain.

Add a new case to the domain
Code: [Select]
int Domain.newCase()
Set a discrete node to a specific state for a given case
Code: [Select]
void DiscreteNode.setCaseState(int c, int state)
When all cases have been created in the Domain, invoke learnTables.

Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on July 26, 2011, 18:48:18
thanks for the quick answer.
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 05, 2011, 17:24:43
I must to add a new case for each state of node with:
"int Domain.newCase() "??
Another, instead of using:
void DiscreteNode.setCaseState(int c, int state)
I used
void LabelledDCNode.setStateLabel(int state, java.lang.String newLabel)
because the state of my node are words and they aren't number
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 07, 2011, 09:28:36
Code: [Select]
int Domain.newCase()This method creates a new empty case in Domain.

Code: [Select]
void DiscreteNode.setCaseState(int c, int state)This method sets the state of a node in a specific case. It is necessary to invoke this method for each node in each case to construct a complete set of cases (i.e., a set of cases with no missing values). You may consider using DiscreteNode.getStateIndex (String) to identify the state index corresponding to a particular String.

Code: [Select]
void LabelledDCNode.setStateLabel(int state, java.lang.String newLabel)This method sets the state label of a LabelledDCNode to newLabel.
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 09, 2011, 18:40:12
Thanks for the quick answer....
My codes generates error :
"Errore: An Api function was called with an invalid argument(e.g., a NULL object was passed to a function that expects a non-NULL argument).
I have written some code that creates the cases in the Domain from your mysql data:

...................
String a;
int p=0;
LabelledDCNode node1 = new LabelledDCNode(myDomain);
node1.setName.........
node1.setLabel...........
......................
Resulset rset = stmt.executeQuery("SELECT ....... FROM .......;")
int statenode1=0;
while(rset.next()){
p.myDomain.newCase();
node1.setCaseState(p,statenode1);
a = rset.getString("node1");
node1.setStateLabel(statenode1,a);
statenode1++;
 }
Resulset rset2............
.........................
.................
myDomain.compile();
myDomain.learnTables();
.............


and I have written some code that print tables for all discrete node
public static void printTable(Table CPT)..........
..................
...................

You could help me solve this problem?
Thanks a lot
P.S. ...and to use the algorythm PC?
I use void Domain.learnStructure() instead learnTable?
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 13, 2011, 13:40:28
The error message ""Error: An Api function was called with an invalid argument(e.g., a NULL object was passed to a function that expects a non-NULL argument)" states that one of the arguments to a HUGIN method is NULL. From your code example it is difficult to say which one. (I assume 
Code: [Select]
p.myDomain.newCase(); is in fact
Code: [Select]
p=myDomain.newCase();).

The error could be caused by "a" being NULL. It is good practice to including error testing code and printing a stack-trace will help to locate the cause of the problem. You should test for NULL arguments before calling HUGIN methods.

The learn the structure of a network using the PC algorithm you invoke "learnStructure ()".
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 13, 2011, 15:15:51
thank you for the quick answer but the error isn't that......
i have the same error
My code complete is:

import java.sql.*;
import java.util.*;
import COM.hugin.HAPI.*;

public class Test{
public static void main (String []args throws ExceptionHugin{
try{
java.lang.Class.forName("com.mysql.jdbc.Driver");
}
catch (Exception exc){
System.out.println("Error - Driver jdbc not present: "+exc.getMessage());
}
try{
String a,b;
Domain myDomain=new Domain();
int p=0;
int q=0;

LabelledDCNode one = new LabelledDCNode(myDomain);
one.setLabel("one");
one.setName("one");
one.setNumberOfStates(40);

LabelledDCNode two = new LabelledDCNode(myDomain);
two.addParent(one);
two.setLabel("two");
two.setName("two");
two.setNumberOfStates(40);

Connection conn = DriverManager.getConnection("url","user","password");
Statement stmt = conn.createStatement();

Resulset rset = stmt.executeQuery("SELECT one FROM table;");
int statenode1 = 0;
while(rset.next()){
p=myDomain.newCase();
one.setCaseState(p,statenode1);
a = rset.getString("one");
//System.out.println(a);
one.setStateLabel(statenode1,a);
statenode1++
}

Resulset rset2 = stmt.executeQuery("SELECT two FROM table;");
int statenode2 = 0;
while(rset2.next()){
q=myDomain.newCase();
two.setCaseState(q,statenode2);
b=rset2.getString("two");
//System.out.println(b);
two.setStateLabel(statenode2,b);
statenode2++
}

myDomain.compile();
myDomain.learnTable();  // or myDomain.learnStructure();

Table t = two.getTable();
printTable(t);

Table t1 = one.getTable();
printTable(t1);

rset.close();
rset2.close();
stmt.close();
conn.close();
}
catch(Exception exc){
System.out.println("Error:"+exc.getMessage());
}
}

public static void printTable(Table CPT) throws ExceptionHugin{
NodeList nodes = CPT.getNodes();
int[] configuration = new int [nodes.size()];
int tableSize = CPT.getSize();
for(int i=0;i<tableSize;i++){
CPT.getConfiguration(configuration,i);
for (int j=0;j<nodes.size();j++){
Node n = (Node)nodes.get(j);
System.out.print(n.getName()+"="+configuration[j]+" ");
}
System.out.println(":= "+CPT.getDataItem(i));
}
}
}




...........If I print a and b, I can see which they are the values ​​of my databases.
I think which the error is generated by learntable() or learnStructure()
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 15, 2011, 10:41:57
I cannot test your code at I do not have a database connection...

The error message indicates an error in a parameter to a HUGIN method. Domain.learnTables and Domain.learnStrcucture does not take any argument. Please test the input values to each HUGIN method invocation.

Here is a working example showing how to enter and learn (CPTs) from data:
Code: [Select]
/*
 * This simple Java program illustrates how to learn (the parameters)
 * of a Bayesian network from data
 *
 * The result is stored in a file name learning.net
 *
 *
 * Author: Anders L Madsen @ HUGIN EXPERT A/S
 *
 * For any questions or comments, please contact the author at
 * alm@hugin.com
 */
import COM.hugin.HAPI.*;
import java.text.DecimalFormat;

class EnterDataExample {
    // the model
    Domain dom = null;

    // the nodes / variables in the model
    LabelledDCNode Sex, Height;

    public EnterDataExample ()
    {
try {
    // Create domain. Done once.
    dom = new Domain ();
   
    Sex = new LabelledDCNode(dom); Sex.setName ("Sex");
    Height = new LabelledDCNode(dom); Height.setName ("Height");

    Sex.setNumberOfStates (2);
    Sex.setStateLabel (0, "Female");
    Sex.setStateLabel (1, "Male");

    Height.setNumberOfStates (2);
    Height.setStateLabel (0, "Low");
    Height.setStateLabel (1, "High");

    // Add Sex as parent of Height. Comment this line if you
    // uncomment "dom.learnStructure ();" below
    Height.addParent (Sex);

    // create Experience tables to enable CPT estimatio
    Sex.getExperienceTable ();
    Height.getExperienceTable ();

} catch (Exception e) {
    e.printStackTrace ();
    System.err.println (e.getMessage ());    
}
    }

    // Data is an array of strings. First entry is Sex and second is
    // Height;
    String dataArray[][]  =
{
    {"Male", "High"},
    {"Male", "High"},
    {"Male", "High"},
    {"Female", "High"},
    {"Female", "Low"},
    {"Male", "Low"},
    {"Female", "Low"},
    {"Male", "High"},
    {"Male", ""},
    {"Female", "Low"}
};
;
    int N=10;

    // Main procedure. 
    protected void doLearning () {
try{
    // enter data
    enterData ();

    // (learn structure) compile and estimate parameters
    // dom.learnStructure (); // uncomment this line (and the
    // addParent line) above to learn structure from data
    dom.compile ();
    dom.learnTables ();

    // save domain in file
    dom.saveAsNet ("learning.net");
} catch (Exception e) {
    e.printStackTrace ();
    System.err.println (e.getMessage ());    
}
    }

    //
    protected void enterData () {
try{
    long j, s;
    for (int i = 0; i < N; i++) {
j = dom.newCase ();

s = Sex.getStateIndex (dataArray[i][0]);
if (s >= 0)
    Sex.setCaseState (j, s);

s = Height.getStateIndex (dataArray[i][1]);
if (s >= 0)
    Height.setCaseState (j, s);
    }
    //... more data
} catch (Exception e) {
    e.printStackTrace ();
    System.err.println (e.getMessage ());    
}
    }
   
    static public void main (String args[])
    {
EnterDataExample ede = new EnterDataExample ();
ede.doLearning ();
    }
}

Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 15, 2011, 15:14:28
thanks a lot.............
I added
one.getExperienceTable();
two.getExperienceTable();
before of myDomain.compile() and now my code is running with learnTable().
If I use learnStructure() (algorithm PC) get the same output:
"Error: An Api function was called with an invalid argument(e.g., a NULL object was passed to a function that expects a non-NULL argument)".

Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 15, 2011, 22:42:00
please send me you updated code.
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 16, 2011, 17:05:58
import java.sql.*;
import java.util.*;
import COM.hugin.HAPI.*;

public class Test{
public static void main (String []args throws ExceptionHugin{
try{
java.lang.Class.forName("com.mysql.jdbc.Driver");
}
catch (Exception exc){
System.out.println("Error - Driver jdbc not present: "+exc.getMessage());
}
try{
String a,b;
Domain myDomain=new Domain();
int p=0;
int q=0;

LabelledDCNode one = new LabelledDCNode(myDomain);
one.setLabel("one");
one.setName("one");
one.setNumberOfStates(40);

LabelledDCNode two = new LabelledDCNode(myDomain);

two.setLabel("two");
two.setName("two");
two.setNumberOfStates(40);

Connection conn = DriverManager.getConnection("url","user","password");
Statement stmt = conn.createStatement();

Resulset rset = stmt.executeQuery("SELECT one FROM table;");
int statenode1 = 0;
while(rset.next()){
p=myDomain.newCase();
one.setCaseState(p,statenode1);
a = rset.getString("one");
//System.out.println(a);
one.setStateLabel(statenode1,a);
statenode1++
}

Resulset rset2 = stmt.executeQuery("SELECT two FROM table;");
int statenode2 = 0;
while(rset2.next()){
q=myDomain.newCase();
two.setCaseState(q,statenode2);
b=rset2.getString("two");
//System.out.println(b);
two.setStateLabel(statenode2,b);
statenode2++
}

two.addParent(one);
one.getExperienceTable();
two.getExperienceTable();
myDomain.compile();
myDomain.learnStructure();

Table t = two.getTable();
printTable(t);

Table t1 = one.getTable();
printTable(t1);

rset.close();
rset2.close();
stmt.close();
conn.close();
}
catch(Exception exc){
System.out.println("Error:"+exc.getMessage());
}
}

public static void printTable(Table CPT) throws ExceptionHugin{
NodeList nodes = CPT.getNodes();
int[] configuration = new int [nodes.size()];
int tableSize = CPT.getSize();
for(int i=0;i<tableSize;i++){
CPT.getConfiguration(configuration,i);
for (int j=0;j<nodes.size();j++){
DiscreteNode n = (DiscreteNode)nodes.get(j);
int h=configuration[j];
System.out.print(n.getStateLabel(h)+" ");
}
System.out.println(":= "+CPT.getDataItem(i));
}
}
}


P.S.On your code EnterDataExample i have two error:
Sex.setCaseState(j,s);   
Height.setCaseState(j,s);

Error:The metod setCaseState(int,int) in the type DiscreteNode is not applicable for the arguments(long,long)
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 16, 2011, 20:26:53
You should not call Domain.compile before Domain.learnStructure. This will make Domain.learnStructure fail. Call Domain.compile after Domain.learnStructure.

Quote
P.S.On your code EnterDataExample i have two error:
Sex.setCaseState(j,s);   
Height.setCaseState(j,s);

Error:The metod setCaseState(int,int) in the type DiscreteNode is not applicable for the arguments(long,long)

I'm using 64-bit version. If you use 32-bit, then change the long to int.
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 18, 2011, 21:50:51
Thank you.
If I call Domain.compile after Domain.learnStructure I have always the same output:
"Error: An API function was called with an invalid argument (e.g., a NULL object was passed to a function that expects a non-NULL argument)."
.......I can't understand wher's this error.

Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 19, 2011, 10:04:04
Put in some error handling code (try-catch with a printStackTrace call) and identify which line produces the error.

Also, it would be useful as debugging to save the data entered into the domain as file - use Domain.saveCases ().

Please reread the example I posted previously and adapt this example to your situation. Notice the method setStateLabel should not be used as part of entering data and read the documentation on setCaseState.

Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 19, 2011, 17:49:28
thank you.
I added try-catch with a printStackTrace call and the output is:
"COM.hugin.HAPI.ExceptionUsage: An API function was called with an invalid argument (e.g., a NULL object was passed to a function that expects a non-NULL argument).
   at COM.hugin.HAPI.ExceptionHugin.throwException(ExceptionHugin.java:115)
   at COM.hugin.HAPI.Domain.learnStructure(Domain.java:1451)
   at Prova.main(Test.java:80)"

to the line 80 of Test.java there is :
myDomain.learnStructure();
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 20, 2011, 12:04:16
What about the data file? If there is no data entered into the domain, then this error message may be produced. Save the cases to file before calling Domain.learnStructure and inspect the file (or post it here).
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 20, 2011, 18:39:24
I think, my error is this, but I cannot understand how I pass cases to the domain.
For the my code, I haven't data file but I have the data of my database.
In the while loops after
p=myDomain.newCase();
I save the cases with Domain.saveCase(String) in a txt file but I have a file empty.
How I save the cases???


Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 21, 2011, 10:13:57
Please read section 11.1 on data and entering data of the HUGIN API Reference Manual and study the example sent to you previously.

You need to use Domain.saveCases (and not Domain.saveCase) to debug.
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 21, 2011, 17:36:22
thanks..........
I used
Domain.saveCases();
and I could see the .dat file:

# - one - two

1 - "car" - #0
1 - #1 - "red"
1 - #2 - #2
1 - #3 - #3
1 - "house" - #4
1 - "computer" - "green"

the. dat file generated doesn't contain all the values but it has in some position #0,#1,#2..............
Why???
If I print with System.out.println() those values I have the right values
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 21, 2011, 18:29:02
Please attach the data file.

The tokens "#0, #1, ..."  refers to state indexes. Chapter 11 of the HUGIN API Reference Manual describes the learning process and the structure of the data files in great detail. PLEASE read this chapter.
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 29, 2011, 16:48:01
thanks....
I have always the same error:
"COM.hugin.HAPI.ExceptionUsage: An API function was called with an invalid argument (e.g., a NULL object was passed to a function that expects a non-NULL argument).
   at COM.hugin.HAPI.ExceptionHugin.throwException(ExceptionHugin.java:115)
   at COM.hugin.HAPI.Domain.learnStructure(Domain.java:1451)
   at Prova.main(Test.java:80)"
In my code:
1 - in the while loop I pass the value of record of my database to the states of nodes
2 - I use Domain.saveCases(java.lang.String fileName, NodeList nodes, int[] cases, boolean caseCounts, java.lang.String separator, java.lang.String missingData) to save the cases in a file "cases.dat"
3 - I use Domain.parseCases(java.lang.String fileName, ParseListener parseListener) to pass the cases stored in "cases.dat" and enters the cases into this Domain.
4 - I use Domain.leanStructure for PC-algorithm
5 - I use Domain.compile()
6 - I use Domain.learnTables()

This is a part of my new code:
...........................
int cases[]=new int[30];
int p=0;
int z=0;
boolean caseCount=true;
int statenode = 0;
NodeList nodes = new NodeList();
nodes.add(one);
nodes.add(two);
Resulset rset = stmt.executeQuery("SELECT one FROM table;");
Resulset rset2 = stmt2.executeQuery("SELECT two FROM table;");

while(rset.next()&&rset2.next()){
p=myDomain.newCase();
cases[z]=p;
one.setCaseState(p,statenode);
two.setCaseState(p,statenode);
a = rset.getString("one");
b = rset2.getString("two");
one.setStateLabel(statenode,a);
two.setStateLabel(statenode,b);
statenode++;
z++
}

two.addParent(one);
myDomain.saveCases("cases.dat",nodes,cases,caseCount," "," ");
myDomain.parseCases("cases.dat",new DefaultClassParseListener());
myDomain.learnStructure();
myDomain.compile();
myDomain.learnTables();
........................
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on September 30, 2011, 09:27:11
PLEASE attach the "cases.dat" file.
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on September 30, 2011, 13:07:05
This is my new file "cases.dat":

#   one   two

1   "car"   "yellow"
1   "pen"   "red"
1   "train"   "white"
1   "bag"     "black"   
1   "house"   "blue"
1   "computer"   "green"

If I use "pen","bag","yellow" and "black" two or three times instead of "train","bag","yellow"and "white", I have values #0,#1,.........

This is my old file "cases.dat":
#  one  two

1  "car"  #0
1  #1  "red"
1  #2  #2
1  #3  #3
1  "house"  #4
1  "computer"  "green"

Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on October 01, 2011, 14:32:51
As described in the example I posted, you should not use "addParent" when invoking "learnStructure".

Page 157 of the HUGIN API Reference Manual states under the description of "learnStructure":

Quote
This function creates directed links (found by the PC algorithm) between the
nodes of domain, which is assumed to contain only discrete chance nodes
and no edges.

Hence, it is an usage error to use "addParent" before invoking "learnStructure".
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on October 03, 2011, 17:48:58
OK..................
Thanks, thanks thanks..........................
Now I have a problem to the print of tables.
I use to the print tables the metod "printTable (Table CPT)" of post "How to pass .dat file using JAVA HUgin API for EM learning.":

//print tables for all discrete chance nodes
    public static void printTable (Table CPT) throws ExceptionHugin {
   NodeList nodes = CPT.getNodes();
   int[] configuration = new int[nodes.size()];
   int tableSize = CPT.getSize();
   for (int i = 0; i < tableSize; i++) {
       CPT.getConfiguration(configuration, i);
       for (int j = 0; j < nodes.size(); j++) {
      Node n = (Node)nodes.get(j);
      System.out.print(n.getName() + "=" + configuration[j] + " ");
       }
       System.out.println(":= " + CPT.getDataItem(i));
       }
    }

Now in output I have the print of table but the values ​​are not equal to those obtained by Hugin GUI:

table of node "one" with hugin GUI:
car          := 0.166667
pen         :=0.5
house     :=0.166667
computer:=0.166667

table of node "one" with hugin java output:
one=0      := 0.16666666666666669
one=1      := 0.16666666666666669
one=2      := 0.16666666666666669
one=3      := 0.16666666666666669
one=4      := 0.16666666666666669
one=5      := 0.16666666666666669

but the value of one=1,one=2,one=3 is "pen" and then I should have a single value with probability value 0.5 as well in hugin gui

Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on October 06, 2011, 18:52:00
Please study again the example I posted earlier. It illustrates how you first create the nodes and their states of the network. Once the nodes are created you either use "learnStructure" followed by "learnTables" or create the structure (using "addParent") and followed by "learnTables" to estimate the parameters from data.

In the code you explicitly create one state for each data item. Also, you assume that each node should have 40 states.
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: jack on October 09, 2011, 14:02:26
ok now everything works well.
But I have yet another question.
I do not know a priori the number of states of the node, but if I don't set first setNumberOfStates I cannot call setStateLabel.
How can I solve this problem?
thaanks,thanks,thanks very very much
Title: Re: How to pass database using JAVA HUgin API for EM learning.
Post by: Anders L Madsen on October 12, 2011, 13:36:18
You need to determine the number of states of each node and their labels prior to creating the Domain object. You cannot do this on the fly (or at least you have to be very careful not to create two or more states for the same label). This best approach is to make two passes through the data. One for determining the number of states and labels and the second pass for entering the data to the Domain object.