7. Functions

Functions are used as placeholders for specific CPTs of classes attributes. They replace the CPT declaration by a specific syntax depending on the type of function used. The first type is the set of functions called aggregators. These functions are used to quantify the information stored in multiple reference slots. The second kind contains deterministic functions and the third probabilistic functions. The last two kinds of functions are not part of the O3PRM specification and are implementation specific. All functions share the same syntax:

<aggregator> ::= ( "=" | "~" ) <word> "(" <parents>, <args> ")"
<parents>    ::= ( <parent> | "[" <parent> (, <parent> )* "]" )
<args>       ::= <word> ( "," <word> )*

The use of = is reserved for deterministic functions and ~ for probabilistic functions. There are only four built-in functions in the O3PRM language that are deterministic functions called aggregators. There are five built-in aggregators in the O3PRM language: min, max, exists, forall and count. Other deterministic functions such as median and amplitude are implemented in aGrUM but they can be implemented in different ways, preventing us from adding them to the O3PRM specification.

7.1. Deterministic Functions

The min and max functions require a single parameter: a list of slot chains pointing to attributes. The attributes must all be of the same type or share some common supertype. If the common type is not an int, then the type’s declaration order is used to compute the min and max values.

class Die {
  type int (1, 6) result {["1/6", "1/6", "1/6", "1/6", "1/6", "1/6"]};
}

class GameOfDice {
  Die[] dice;
  type int (1, 6) snake_eyes = min( dice.result );  
  type int (1, 6) bingo = max( [ dice.result ] );  
}

If there is only one element in the list of slot chains the [] are optional.

The exists and forall require two parameters: a list of slot chains and a value. As for min and max, all attributes referenced in the slot chains list must share a common type or supertype. The value must be a valid value of that common supertype. exists and forall attribute type must always be a boolean.

class BWPrinter {
  boolean black   { [ 0.2, 0.8 ] };
}

class ColorPrinter {
  boolean magenta { [ 0.8, 0.2 ] };
  boolean cyan    { [ 0.8, 0.2 ] };
  boolean yellow  { [ 0.8, 0.2 ] };
  boolean black   { [ 0.8, 0.2 ] };
}

class PrinterMonitor {
  BWPrinter[] bw;
  ColorPrinter[] color;

  boolean has_magenta = exists ([color.magenta], true);
  boolean has_cyan = exists ([color.cyan], true);
  boolean has_yellow = exists ([color.yellow], true);
  boolean color = forall([color.black, color.magenta, color.cyan, color.yellow], true);
  boolean black = exists( [ bw.black, color.black ] };
}

The count aggregator counts how many times a given outcome occurred. Its type must be of the form type int (0, N), where N is a positive integer. The outcome N must be interpreted as “the outcome occurred at least N times”.

class Die {
  type int (1, 6) result {["1/6", "1/6", "1/6", "1/6", "1/6", "1/6"]};
}

class GameOfDice {
  Die[] dice;
  type int (0, 4) four_six = count( dice.result, 6 );  
}

7.2. Probabilistic Functions

Instead of generating CPTs filled with 0 and 1, like deterministic functions, probabilistic functions return conditional distributions following a specific rule. A classic probabilistic function is the noisy-or, which is implemented in aGrUM as shown below:

class NoisyOr {
  SomeIface iface;
  SomeIface jface;
  boolean state ~ noisy_or([iface.state, jface.state], [0.2, 0.1], 0.4);
}

As for deterministic functions, the first parameter must be a list of parents. For the noisy-or, the next parameter is a list of weights and the third the noise. These functions are not part of the O3PRM specification and you should check your interpreter documentation for their proper syntax.