next up previous
Next: Functions Up: IBAL Tutorial Previous: Defining Variables

Blocks and Libraries

Defining an entire Bayesian Network in a single let expression as above can be quite cumbersome. Fortunately there is a convenient alternative. You can simply define each variable in turn on the IBAL command line:

IBAL> burglary = flip 0.01
IBAL> earthquake = flip 0.001
IBAL> alarm = case <burglary, earthquake> of \
    > # <false, false> : flip 0.01 \
    > # <false, true> : flip 0.1 \
    > # <true, false> : flip 0.7 \
    > # <true, true> : flip 0.8

In general, you can define any variable at the command line with a definition of the form x = e, where x is an identifier, and e is an expression. A definition is just one form of declaration; we will see others later. After a variable has been defined, it is available for use in future definitions or declarations. Note that IBAL does not evaluate anything after you enter the definition. Instead, the defining expression is stored and referred to when needed.

One can also collect a sequence of declarations in a block. A block has the form { d_1 ; ...; d_n } where the d_i are declarations. Note that a block is surrounded by curly braces, and the declarations are separated by semi-colons. A block is actually an expression, whose result is a tuple containing all the variables defined in the block. Variables defined in earlier declarations are available for use in later declarations.

Blocks give us the means to define the notion of a probabilistic object, as used in object-oriented Bayesian networks. An object is an entity with a number of attributes. The attributes of an object may be simple, or they may themselves be other objects. The model of the object indicates how the various attributes depend on each other probabilistically. There are three kinds of attributes: inputs, which are defined outside the object and used within it; outputs, which are defined inside the object and available outside it; and encapsulated attributes, which are defined for use only within the object itself. In IBAL, an object is defined by creating a block with a definition for every output and encapsulated attribute. To indicate that an attribute is encapsulated, the keyword private is used before the definition. Variables used in the definitions within a block that are not themselves defined in the block are inputs.

For example, we can define a simple model describing the performance of a student in a course. First we create objects representing the student, and course, then create a performance object that depends on both of them. The course object itself depends on two other objects, the professor and the field of the course. In this model, we assume that the professor's field is the same as that of the course.

student = {
  smart = flip 0.4; 
  hard_working = flip 0.7;
  good_test_taker = if smart then flip 0.8 else flip 0.3 
};

field = {
  hard = flip 0.5;
  high_standards = flip 0.3
};

prof = {
  private mean = flip 0.1;
  clear = ~ mean & (if field.hard then flip 0.5 else flip 0.8)
};

course = {
  well_taught = (prof.clear | ~ field.hard) & flip 0.9
};

performance = {
  private understands = 
    if student.hard_working
    then case <student.smart, course.well_taught> of
    # <true, true> : flip 0.95
    # <false, false> : flip 0.35
    # _ : flip 0.7
    else case student.smart of
    # true : flip 0.7
    # false : flip 0.1;

  exam_grade = 
    case <understands, student.good_test_taker> of
    # <true, true> : dist [ 0.6 : 'A, 0.3 : 'B, 0.1 : 'C ]
    # <true, false> : dist [ 0.4 : 'A, 0.2 : 'B, 0.4 : 'C ]
    # <false, true> : dist [ 0.5 : 'A, 0.2 : 'B, 0.3 : 'C ]
    # <false, false> : dist [ 0.1 : 'A, 0.4 : 'B, 0.5 : 'C ];

  homework_grade =
    case <understands, student.hard_working> of
    # <true, true> : dist [ 0.6 : 'A, 0.3 : 'B, 0.1 : 'C ]
    # <true, false> : dist [ 0.4 : 'A, 0.2 : 'B, 0.4 : 'C ]
    # <false, true> : dist [ 0.5 : 'A, 0.2 : 'B, 0.3 : 'C ]
    # <false, false> : dist [ 0.1 : 'A, 0.4 : 'B, 0.5 : 'C ];
}

In the above example, each of the blocks defines a single object. We will see in the next section how to use blocks in functions to define classes of objects.

Block notation is actually the most convenient way to create larger models. As models get larger, it is more convenient to create them in a file rather than type them in at the command line. Libraries allow you to do that. A library has the form of a block, without the surrounding curly braces. The standard suffix for IBAL libraries is .ibl.

For example, the above block is contained in a file named oobn1.ibl in the Examples directory. To load it into IBAL, use the command :l oobn1, or :l oobn1.ibl. (In general, commands at the IBAL prompt begin with a colon. You can use :? to see a list of available commands.) This creates a variable called oobn1, and defines it to be the contents of oobn1.ibl. You can now access any of the variables defined in oobn1.ibl as components of the variable block. For example, you could ask for the joint probability of a student's smartness and their exam grade with

< oobn1.student.smart, oobn1.performance.exam_grade >
In general, one can use this method to ask arbitrary queries on a model. In the case of a Bayesian network, IBAL's inference algorithm amounts to performing variable elimination, which is a standard Bayesian network inference algorithm. Future plans for IBAL include implementing approximate Bayesian network inference algorithms as an alternative.

You can also load libraries on the UNIX command line. Any library to be loaded can be passed as an additional argument to IBAL. The .ibl suffix will be added automatically if it is not present. So, for example, ibal alarm will load the alarm.ibl library. All definitions in alarm.ibl will be available as part of an alarm variable. Furthermore, if multiple libraries are loaded, the contents of earlier libraries are available to later ones in a similar way.

One can also save the contents of the current IBAL session in a library. Entering :s filename creates a library named filename, containing the declarations that have been entered in the current IBAL session.

It is also possible to create a file containing an expression (as opposed to a library), and evaluate it. This is achieved by using the -b option to IBAL. The file to be evaluated will be the last one on the command line, and it may be preceded by libraries. For example, look at the contents of file1.ibl, file2.ibl and file3.ibl in the Examples directory, and run ibal -b file1 file2 file3.

A word about paths. IBAL uses a path variable defined in global.ml to tell it where to look for files. By default it looks first in the current directory, and then in the Examples subdirectory of the IBAL distribution. You can change the path in three ways. To change it permanently, just edit the definition of path in global.ml and recompile IBAL. Alternatively, you can add a directory to the front of the path using the -i command line argument, followed by the directory, with no space between the -i and the directory. Finally, you can add a directory in the IBAL interpreter, using the :i command, followed by the directory.


next up previous
Next: Functions Up: IBAL Tutorial Previous: Defining Variables
Avi Pfeffer 2006-11-19