6. Code generation and exporting of controllers

Besides the various routines for analysis and execution of controllers constructed with TuLiP, it is also possible to automatically generate implementations in formats appropriate for use in other contexts. We refer to this process as exporting. Here we provide descriptions and examples of the various exporting routines available.

6.1. python_case

Given a Mealy machine (Sec. 3.3 in [LS11]) as would be obtained, for example, from an invocation of tulip.synth.synthesize, the function python_case in tulip.dumpsmach generates an implementation as a standalone Python class. The class implements the machine by

  • tracking the current state of the machine and

  • providing a move method that accepts the input of the machine and returns the appropriate output as a dictionary in which the output variable names are keys.

Calls to move cause the internal state to transition. The machine can be reset to its initial state by manually calling the __init__ method or effectively by creating a new instance. Note that the internal state is entirely represented by the attribute state. Thus it is possible to save a copy of the current state of the machine and return to it later. E.g., the output that would be obtained if some inputs were applied can be discovered by the following idiom.

import copy
saved_state = copy.copy(M.state)
sample_outputs = M.move(**sample_inputs)
M.state = saved_state

The generated code does not depend on tulip; that is, it can run without TuLiP being installed. As such, we refer to it as being “standalone”.

6.1.1. Example

Consider the script examples/robot_planning/gr1.py as distributed with TuLiP. At the end of the script, there is an object named ctrl that is an instance of MealyMachine. It represents the controller that was constructed automatically (or “synthesized”) according to the specification. Append the following code to the end of the script gr1.py. (Alternatively, if IPython is installed, then first run ipython -i gr1.py, and then enter the following.)

from tulip import dumpsmach
dumpsmach.write_python_case("gr1controller.py", ctrl, classname="ExampleCtrl")

The first line merely loads the dumpsmach module. The second line calls a function that, in turn, calls python_case and saves the result to a file named “gr1controller.py”. That file contains a class named “ExampleCtrl” that implements ctrl, as demonstrated by the following script.

from __future__ import print_function
from gr1controller import ExampleCtrl

M = ExampleCtrl()
print('In order, the input variables: '+', '.join(M.input_vars))
for i in range(10):
    input_values = {"park": 0}
    print(M.move(**input_values))

Alternatively, the above code can be modified by calling M.move with the input variable names as keyword parameters:

print(M.move(park=0))