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
).