5. Class Declaration

Classes are the placeholder of attributes and references in the O3PRM language. You can see them as fragments of Bayesian Networks.

<class>         ::= class <word> [ extends <word> ] "{" <class_elt>* "}"
<class_elt>     ::= <reference_slot> | <attribute> | <parameter>

Classes contain three different elements: attributes, reference slots and parameters.

5.1. Attributes

Attributes are a generic definition of random variables. They are not random variables: only their instances after instantiating the class are random variables. Attributes are defined by a type, a name, a set of parents and a CPT.

<attribute>      ::= <attribute_type> <attribute_name> <attribute_cpt> ";"
<attribute_type> ::= <anonymous_type> | <word>
<anonymous_type> ::= <labelized_type> | <integer_type> | <real_type>
<attribute_name> ::= <word> [ <dependency> ]
<attribute_cpt>  ::= ( <CPT> | <aggregator> )
<dependency>     ::= dependson <parent> ( "," <parent> )*

<CPT>      ::= "{" ( <raw_CPT> | <rule_CPT> ) "}"
<raw_CPT>  ::= "[" <cpt_cell> ( "," <cpt_cell> )+ "]"
<rule_CPT> ::= ( <word> ("," <word>)* ":" <cpt_cell> ";" )+
<cpt_cell> ::= <float> | """ <formula> """
<formula>  ::= <real> | <function> | <formula> <operator> <formula>
<function> ::= <function_name> "(" <formula> ")"
<function_name> ::= exp | log | ln | pow | sqrt

5.1.1. Tabular Declaration

When declaring a CPT in tabular form, the probability values for all the possible values of the attribute and its parents must be specified. In addition, the order in which the values are specified is important. The O3PRM language uses a declaration by column, i.e., in each column of the CPT, the values must sum to one because the rows of the CPT correspond the domain of the attribute for which the CPT is specified (please, note that the terms column and row are used loosely since the table is only one-dimensional). The following example illustrates the reason why we say that the columns sum to one:

class Example {
  boolean Y {[0.2, 0.8]};
  boolean Z {[0.5, 0.5]};
  boolean X dependson Y, Z {[
  //     Y==false      |        Y==true
  // Z==false | Z=true | Z==false | Z==true
       0.2,     0.3,       0.7,     0.9,    // X == false
       0.8,     0.7,       0.3,     0.1     // X == true
  ]};
}

In this example, we can see that the first value is the probability P(X=false|Y=false,Z=false), the second value P(X=false|Y=false,Z=true), the third P(X=false|Y=true,Z=false) and so on.

5.1.2. Rule-based CPT declaration

Rule-based declarations exploit the * wildcard symbol to reduce the number of parameters needed to specify the CPT.

class Example {
  boolean Y {[0.2, 0.8]};
  boolean Z {[0.5, 0.5]};
  boolean X dependson Y, Z {
    // Y,    Z:   X=false, X=true
       *,  false:  1.0,     0.0;
      true, true:  0.01,    0.99;
     false, true:  0.3,     0.7;
};

The first line uses the wildcard * for Y’s outcomes. This defines in one line the set of probabilities P(X|Y=y,Z=false) for y in {false,true}. There is no limit in the number of rules and, when two rules overlap, the last one takes precedence.

5.2. Reference Slots

Reference slots can either be simple (defining a one to one relation, or a unary relation) or complex (defining a one to N relation, or n-ary relation).

<reference_slot> ::= [internal] <word> [ "[" "]" ] <word> ";"

5.2.1. Simple Reference Slots

Simple reference slots are used to define a one to one relation between two classes. They are used in slot chains to add parents from other classes to an attribute.

class SomeClass {
  boolean Y {[0.2, 0.8]};
  boolean Z {[0.5, 0.5]};
}

class AnotherClass {
  SomeClass myClass;
  boolean X dependson myClass.Y, myClass.Z {
    // Y,    Z:   X=false, X=true
       *,  false:  1.0,     0.0;
      true, true:  0.01,    0.99;
     false, true:  0.3,     0.7;
};

Class AnotherClass defines the reference slot myClass of type SomeClass and its attribute X uses two slot chains, myClass.Y and myClass.Z, to reference its parents.

Note that if reference cycles are allowed, you must be careful to not create cycles between attributes. Indeed, if there exists a cycle between two attributes, this implies that the CPT of the first one is conditional given the second attribute and the CPT of the second attribute is conditional given the first attribute. As a consequence, it is not possible to define a joint probability distribution using these two CPTs. The problem is exactly the same for regular Bayesian Networks and it explains why directed cycles are forbidden in BNs.

5.2.2. Complex Reference Slots

Complex reference slots are used to define n-ary relations between classes. They can be used in slot chains when declaring aggregators, special attributes described in section 5.

class SomeClass {
  boolean Y {[0.2, 0.8]};
  boolean Z {[0.5, 0.5]};
}

class AnotherClass {
  SomeClass[] myClass;
  boolean X = or([myClass.Y, myClass.Z]);
}

To declare a complex reference slots we use [] as a suffix to the reference slot type. In the above example, we declared an or aggregator referencing attributes Y and Z accessed though the complex reference myClass. Since myClass is a complex reference slot, we will be able to reference more than instance of SomeClass. Since we do not know how many parents there is for attribute X, we need to use an aggregator to generate the attribute’s CPT when instantiating the class containing the attribute.

5.3. Parameters

Parameters are used to define constants used in the CPT generation. For example, if we define two parameters such as lambda and t, we will be able to write the following formula in a CPT: 1-exp(-lambda*t).

class ClassWithParams {
  param real lambda default 0.003;
  param int t default 8760;
  boolean state {
    ["exp(-lambda*t)", "1-exp(-lambda*t)" ]
  };
}

The default keyword is mandatory to provide a default value to parameters, since they can be changed when declaring an instance of a class with parameters.