— INFORMATION FOR DEVELOPERS —

Creating combinational blocks

Feel free to skip this chapter. The FuncBlock is an universal combinational block and there is very little reason to write a new one.

Directions

Directions for creating a new CBlock:

  1. subclass from CBlock

  2. define CBlock.calc_output()

  3. optional: define CBlock.start() and CBlock.stop()


abstract CBlock.calc_output() Any

Compute and return the output value. This is supposed to be a pure function with inputs retrieved from the CBlock._in described below.

CBlock._in

An object providing access to input values.

An input value can be retrieved using the input name as a key self._in['myinput'] or as an attribute self._in.myinput.

The result is a single value or a tuple of values if the input is a group.

CBlock.start() None

Pre-simulation hook.

start() is called when the circuit simulation is about to start.

By definition CBlocks do not require any preparations. start() typically just checks the input signature. A signature check is optional, but recommended, because it catches possible errors early and gives clear problem descriptions.

Important

When using start(), always call the super().start().

CBlock.stop() None

Post-simulation hook.

stop() is called when the circuit simulation has finished, but only if start() was successfully called.

By definition CBlocks do not require cleanup, so stop() is rarely used. A possible use-case might be processing of some gathered statistics data.

An exception in stop() will be logged, but otherwise ignored.

Important

When using stop(), always call the super().stop()

Input signatures

An input signature is a dict with the following key:value structure:

  • key = the input name (string)

    The reserved group name '_' represents the group of unnamed inputs, if any.

  • value = None or integer:

    • None - if the input is a single input

    • the number of inputs in a group - if the input is a group

CBlock.input_signature() dict[str, None | int]

Return the input signature. The data is available after connecting the inputs with CBlock.connect().

An EdzedInvalidState is raised when called before connecting the inputs.

CBlock.check_signature(esig: Mapping[str, None | int | Sequence[int]]) dict

Compare the expected signature esig with the actual one.

For a successful result items in the esig and items from CBlock.input_signature() must match.

If no problems are detected, the input signature data is returned for eventual further analysis.

If any mismatches are found, a ValueError with a description of all differences (missing items, etc.) is raised. check_signature() tries to be really helpful in this respect, e.g. it provides suggestions for probably mistyped names.

In order to support variable input group sizes, the expected size may be given also as a range of valid values using a sequence of two values [min, max] where max may be None for no maximum. min may be also None for no minimum, but zero - the lowest possible input count - has the same effect.

Examples of esig items:

# single vs group
'input1': None         # a single input (not a group)
'input2': 1            # a group with one input (not a single input)
# number of inputs in a group
'group1': 4            # exactly 4 inputs
'group2': [2, None]    # 2 or more inputs
'group3': [0, 4]       # 4 or less
'group4': [None, None] # input count doesn't matter

Example (Invert)

Invert source:

class Invert(edzed.CBlock):
    def calc_output(self):
        return not self._in['_'][0]

    def start(self):
        super().start()
        self.check_signature({'_': 1})