The State Class

The decomposable Python model is defined by the State class. The class must be named State, it cannot be a subclass (even of object), and it must have an __init__ constructor method with no extra parameters. For the model to receive external inputs, at least one method starting with receive_ should be present. To impose constraints on the valid inputs, some optional corresponding validate_ methods can be added:

class State:
    def __init__(self):
        self.sum : int = 0
    def receive_Reset(self):
        self.sum : int = 0
    def receive_Update(self, x : int):
        self.sum : int = self.sum + x
    def validate_Update(self, x : int):
        return x > 0

The __init__ constructor declares all the state variables and initializes them. It can only receive a single self argument and only constant value assignments to the self attributes are allowed inside the constructor body. These assignment statements also act as state variable declarations - you can only reference the self attributes that you declared in the constructor:

class State:
    def __init__(self):
        self.y : int = 11
    def receive_Update(self):
        self.x : int = 10 # ERROR: undeclared attribute self.x
        self.y : int = 42

The attributes must be unique and explicitly initialized with some initial values.

Adding a receive_ActionName method to the State class creates an ActionName action. Arguments of such methods are defining the parameters of the actions. For example:

class State
    def __init__(self):
        self.x : int = 0
    def receive_Reset(self, value : int):
        self.x : int = value
    def receive_Multiply(self, value : int , twice : bool):
        self.x : int = value * self.x
        if twice:
            self.x : int = 2 * self.x

In this class we’ve declared two actions: the Reset action has a value integer parameter, and the Multiply action has two parameters - another value integer and a twice boolean value. Each argument must have an associated type hint. Default argument values are not allowed, as well as variable-length (*args) and keyword arguments (**kwargs ).

To constrain the parameter space of the incoming action, one can declare a validate_ method for the same action name. Such a method must accept the same list of parameters as the corresponding receive_ method and must return a boolean value: returned True means that the values of the action are allowed.

def validate_Reset(self, value : int):
    return value > 0
def validate_Multiply(self, value : int , twice : bool):
    if twice:
         return value > 0
        return True

Above we’ve constrained the value parameter of the Reset method to always be positive. While the value parameter of the validate_Multiply method is required to be positive only when the twice parameter is True.