), that's why they are called Functional
diracs.
We describe now how to implement this kind of kernels on ProBT. Before
we go on creating a functional dirac we need to define an ProBT external
function, that is,
in the previous definition. Generally speaking
there are two ways of creating external functions, either by using a
C++ function with the following prototype
void user_function(plValues &output_values,
const plValues &input_values)
or a method of an object class
object_class::class_method(plValues &output_values,
const plValues &input_values)
In the following example we illustrate the construction of external functions and functional diracs.
1 /*=============================================================================
2 * File : addDice.cpp
3 *=============================================================================
4 *
5 *------------------------- Description ---------------------------------------
6 * This program shows the use of external functions by means of C++ functions
7 * The construction of a functional dirac is also shown.
8 * The program gives the possible values of each of the dice given the sum of
9 * points.
10 *-----------------------------------------------------------------------------
11 */
12
13 #include <pl.h>
14
15 void add_dice(plValues &dice_addition, const plValues &die) {
16 unsigned int n_dice; // Number of dice
17 unsigned int sum=0; // sum of points
18 unsigned int i;
19
20 n_dice = die.size(); // Get the number of dice
21
22 for(i=0;i<n_dice;i++) // Compute the sum of points
23 sum = sum+die[i];
24
25 dice_addition[0] = sum; // Set the output values
26 }
27
28
29 main()
30 {
31 /**********************************************************************
32 Defining the variable type, set and values plus the kernel for the
33 variable set
34 ***********************************************************************/
35
36 unsigned int number_of_dice; // Stores the number of dice
37
38 cout<<"Give me the number of dice: ";
39 cin>>number_of_dice;
40
41 plIntegerType die_type(1,6); // die type [1,2,...,6]
42 plIntegerType dice_sum(number_of_dice,
43 number_of_dice*6);// Sum type [n,n+1,...,n*6]
44 plSymbol points("Addition",dice_sum); // Variable space for the addition
45 plArray dice("Die",die_type,1,
46 number_of_dice); // Variable space for the dice
47
48 plValues result(dice^points); // Values storing the result of the
49 // dice and the addition
50
51 /**********************************************************************
52 Writing the joint distribution
53 ***********************************************************************/
54
55 // P(Die0 Die1 ... Die(n-1)) = Uniform(Die0 Die1 ... Die(n-1))
56 plUniform p_dice(dice);
57
58 // Create the external function
59 plExternalFunction sum(points,dice,add_dice);
60
61 // P(points=p | Die0=die0 Die1=die1 ... Die(n-1)=die(n-1)) =
62 // 1 if points = add_dice(die0,die1,...,die(n-1)) else 0
63 plFunctionalDirac p_addition(points,dice,sum);
64
65 // P(Die0 Die1...Die(n-1) points)=
66 // P(Die0 Die1 ... Die(n-1))
67 // P(points | Die0 Die1...Die(n-1))
68 plJointDistribution dice_jd(dice^points,p_dice*p_addition);
69
70 /**********************************************************************
71 Making a question P(Die0 Die1 ... Die(n-1)| points = v)
72 ***********************************************************************/
73
74 plCndKernel cnd_question;
75 plKernel question;
76 int v;
77
78 // Get P(Die0 Die1 ... Die(n-1) | points )
79 dice_jd.ask(cnd_question,dice,points);
80 cout<<"Give me the total number of points: ";
81 cin>>v;
82 result[points] = v;
83
84 // Get P(Die0 Die1 ... Die(n-1) | points=v)
85 cnd_question.instantiate(question,result);
86
87 /**********************************************************************
88 Tabulate the result of the question
89 ***********************************************************************/
90
91 cout<<"\nThe possibilities are :\n";
92 question.tabulate(cout,false);
93 }
The solution is given by Program 12. Once we know the
number of dice, line 39, we can proceed to define the variable types,
sets and values, lines 41 to 50. The joint distribution of the model
is written at lines 51 to 69. Observe that the external function is
created at line 59. The two first arguments correspond respectively to
the output and input parameters of the function. In this case
points
and
dice
. The third argument is the C++ function
coded at lines 14 to 26. The add_dice function computes the
total number of points given the values of each of the dice. From line
59 in the add_dice function addition corresponds to
points and die to dice. Accordingly, the references
die_addition[0] affects the value of
, die[0]
that of Die0,
die[1] that of Die1 and so on. Note that, the access to
the variable sets is made by using the index of the variables and not
a plSymbol. The function add_dice is general for any
number
of dice, where
is given by die.size(). After
line 63, p_addition programs a generalization of
expression 4.1 for
dice. The question
is produced by lines 70 to 86. The final
lines 87 to 92 tabulate the resulting question distribution. The
second argument of the
tabulate method in line 92 indicates that the variable values
of
with a zero probability should not be printed.
Here is a sample output of Program 12:
Give me the number of dice: 3 Give me the total number of points: 15 The possibilities are : 3 6 6 0.00462963 4 5 6 0.00462963 4 6 5 0.00462963 5 4 6 0.00462963 5 5 5 0.00462963 5 6 4 0.00462963 6 3 6 0.00462963 6 4 5 0.00462963 6 5 4 0.00462963 6 6 3 0.00462963
Note that just the values with probability different to zero has been printed out and that the probabilities are not normalized.
A second version of Program 12, using an object class
method, can be easily obtained by substituting the C++ function
add_dice at lines 15 to 26 by
class dice_analyzer {
public:
void dice_analyzer::add_dice(plValues &addition, const plValues &die) {
unsigned int n_dice; // Number of dice
unsigned int sum=0; // sum of points
unsigned int i;
n_dice = die.size(); // Get the number of dice
for(i=0;i<n_dice;i++) // Compute the sum of points
sum = sum+die[i];
addition[0] = sum; // Set the output values
}
};
and writing,
dice_analyzer my_analyzer; plExternalFunction sum(points,dice_set, &my_analyzer, &dice_analyzer::add_dice);
instead of line 59. Observe that, the third argument of the
plExternalFunction constructor has been replaced by two
arguments: one pointing to an instance of the object class
(&my_analyzer); and the other pointing to the method on the
class (&dice_analyzer::add_dice).