You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
heptagon/manual/heptreax-manual.tex

590 lines
22 KiB
TeX

\documentclass[a4paper]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[a4paper,margin=2cm]{geometry}
%\usepackage[francais]{babel}
%\usepackage{subfigure}
%\usepackage{fancyvrb}
%\usepackage{fancyhdr}
\usepackage{hyperref}
\usepackage{tabularx}
\usepackage{xcolor}
\usepackage{helvet}
%\usepackage{comment}
%\usepackage{lmodern}
\usepackage{varwidth}
\usepackage{tikz}
\usetikzlibrary{arrows,calc}
\usetikzlibrary{automata}
\usepackage{tikz-timing}
%\usetikzlibrary{matrix}
%\usetikzlibrary{shapes}
%\usetikzlibrary{positioning}
\usepackage{macros}
\usepackage{listings}
\usepackage{mathpazo}
% fontes tt avec gras (mots-clés)
\renewcommand{\ttdefault}{txtt}
\definecolor{deepgreen}{rgb}{0.09,0.32,0.09}
\definecolor{deepyellow}{rgb}{0.6,0.6,0}
\definecolor{kwcolor}{rgb}{0.6,0.1,0.1}
\lstset{
language=Heptagon,% numbers=left, numberstyle=\small,
basicstyle=\normalsize\ttfamily,captionpos=b,
keywordstyle=\color{kwcolor},
frame={tb}, rulesep=1pt, columns=fullflexible,
xleftmargin=1cm, xrightmargin=1cm,
mathescape=true
}
\tikzset{>=stealth'}
\tikzset{
format/.style={rectangle,draw,color=blue,fill=blue!10},
tool/.style={rectangle,draw,color=red,fill=red!10,rounded corners}
}
\title{Programming and controller synthesis with Heptagon/BZR and ReaX}
\author{Nicolas Berthier \and Gwenaël Delaval}
\date{}
\begin{document}
\maketitle
\section{Introduction}
Heptagon/BZR\footnote{\url{http://bzr.inria.fr}}\cite{delaval13:bzr_jdeds}
is a reactive language, belonging to the synchronous languages family,
whose main feature is to include discrete controller synthesis within
its compilation.
It is equipped with a behavioral contract mechanisms, where
assumptions can be described, as well as an ``enforce'' property part:
the semantics of this latter is that the property should be enforced
by controlling the behaviour of the node equipped with the
contract. This property will be enforced by an automatically built
controller, which will act on free controllable variables given by the
programmer.
ReaX\footnote{\url{http://reatk.gforge.inria.fr}}\cite{berthier14:_reax}
is a controller synthesis tool, dedicated to the control of
logico-numerical programs.
This report documents the integration of these two tools.
\section{Heptagon/BZR in a (small) nutshell}
Heptagon is a synchronous dataflow language, with a syntax allowing the
expression of control structures (e.g., switch or mode automata).
A typical Heptagon program will take as input a sequence of values,
and will output a sequence of values. Then, variables (inputs, outputs
or locals) as well as constants are actually variable or constant
\emph{streams}. The usual operators (e.g., arithmetic or Boolean
operators) are applied pointwise on these sequences of values.
Heptagon programs are structured in \emph{nodes}, which are provided
with \emph{inputs} and \emph{outputs}, and possibly local variables. A
node is defined by mean of a set of \emph{parallel equations},
defining the local variables and outputs' current values, as functions
of current inputs, other variables' values, and current state.
Figure~\ref{fig:hept-exple} shows a short Heptagon example. It
consists of a two-mode automaton, with a mode \emph{Up} in which the
output is increased by the current input value, and a mode \emph{Down}
in which the output is decreased. The output \texttt{y}'s current
value is defined as the current value of the local variable
\texttt{x}, whose last value is recorded sp as tp be used in the
computation performed on the next step. In the \texttt{Up}
(resp. \texttt{Down}) mode, \texttt{x} is defined as the value of
\texttt{x} at the previous instant, increased (resp. decreased) by the
current value of the input \texttt{v}. The automaton stays in the
\texttt{Up} mode until \texttt{x} is greater or equal 10; meaning that
when this condition is true, the next mode will be the mode
\texttt{Down}.
\begin{figure}[hbp]
\centering
\begin{lstlisting}
node twomodes(v:int) returns (y:int)
var last x : int = 0;
let
y = x;
automaton
state Up
do x = last x + v
until x >= 10 then Down
state Down
do x = last x - v
until x <= 0 then Up
end
tel
\end{lstlisting}
\scalebox{1.5}{
\begin{tikztimingtable}
v & 2D{2} D{1} D{5} D{2} D{1} D{0} D{3}\\
State & 4D{\texttt{Up}} 4D{\texttt{Down}}\\
\texttt{twomodes}(v) & D{2} D{4} D{5} D{10} D{8} 2D{7} D{4}\\
\end{tikztimingtable}
}
\caption{Heptagon short example}
\label{fig:hept-exple}
\end{figure}
The Heptagon/BZR language provides a \emph{contract} construct,
allowing the expression of assumptions on the environment (inputs)
(\texttt{assume} keyword), and guaranteed or enforced properties
(\texttt{enforce} keyword) on the outputs.
For example, the \texttt{twomodes} node given above can be enriched
with a contract, saying that if for every instant, $0 \leq \mathtt{v}
\leq 1$, then the property $0 \leq \mathtt{twomodes(v)} \leq 10$ will always hold (Fig.~\ref{fig:exple-contract}).
\begin{figure}[htbp]
\centering
\begin{lstlisting}
node twomodes (v:int) = (y:int)
contract
assume (v <= 1) & (v >= 0)
enforce (o <= 10) & (o >= 0)
var last x : int = 0;
let
y = x;
automaton
state Up
do x = last x + v
until x >= 10 then Down
state Down
do x = last x - v
until x <= 0 then Up
end
tel
\end{lstlisting}
\caption{Example of contract in Heptagon/BZR}
\label{fig:exple-contract}
\end{figure}
Contracts can also be provided with a declaration of
\emph{controllable variables}: these variables are local to the node,
and their value can be used into it. However, these variables are not
defined by the programmer. Their value will be given, during
execution, by a \emph{controller}, which will be computed offline by a
\emph{controller synthesis tool}.
Figure~\ref{fig:exple-contvar} shows how the \texttt{twomodes} node
can be equipped with a controllable variable \texttt{c}, which will
\emph{control} the transition between the two modes.
\begin{figure}[htbp]
\centering
\begin{lstlisting}
node twomodes (v:int) = (y:int)
contract
assume (v <= 1) & (v >= 0)
enforce (o <= 10) & (o >= 0)
with (c:bool)
var last x : int = 0;
let
y = x;
automaton
state Up
do x = last x + v
until c then Down
state Down
do x = last x - v
until c then Up
end
tel
\end{lstlisting}
\caption{Contract with one controllable variable}
\label{fig:exple-contvar}
\end{figure}
We will see in the following sections how these contracts can be
handled by the ReaX verification and synthesis tool.
\section{Integration of Reax and Heptagon/BZR}
\subsection{Compilation chain}
Figure~\ref{fig:bzreax-compil} describes the full compilation process,
involving the Heptagon/BZR compiler (\texttt{heptc}) and the ReaX
controller synthesis tool.
\begin{figure}
\centering
\begin{tikzpicture}[node distance=2cm]
\node[format] (Heptagon) {\begin{tabular}{c}Heptagon\\\texttt{.ept}\end{tabular}};
\node[tool,below of=Heptagon] (Heptc) {\begin{tabular}{c}Heptagon compiler\\\texttt{heptc}\end{tabular}};
\node[format,below of=Heptc] (Ctrln) {\begin{tabular}{c}Ctrl-n equations\\\texttt{.ctrln}\end{tabular}};
\node[tool,below of=Ctrln] (ReaX) {\begin{tabular}{c}ReaX synthesis tool\\\texttt{reax}\end{tabular}};
\node[format,below of=ReaX] (Controller) {\begin{tabular}{c}Controller function\\\texttt{.ctrlf}\end{tabular}};
\node[tool,below of=Controller] (Ctrl2ept) {\begin{tabular}{c}Controller compiler\\\texttt{ctrl2ept}\end{tabular}};
\node[format,below of=Ctrl2ept] (HeptagonCtrlr) {\begin{tabular}{c}Heptagon\\\texttt{.ept}\end{tabular}};
\node[tool,below of=HeptagonCtrlr] (HeptcCtrlr) {\begin{tabular}{c}Heptagon compiler\\\texttt{heptc}\end{tabular}};
\node[format,below left of=HeptcCtrlr,node distance=3cm] (C) {\begin{tabular}{c}C program\\\texttt{.c}\end{tabular}};
\node[format,below right of=HeptcCtrlr,node distance=3cm] (Java) {\begin{tabular}{c}Java program\\\texttt{.java}\end{tabular}};
\node[tool,below of=C] (Gcc) {\begin{tabular}{c}C compiler\\\texttt{gcc}\end{tabular}};
\node[tool,below of=Java] (Javac) {\begin{tabular}{c}Java compiler\\\texttt{javac}\end{tabular}};
\coordinate (Middle) at ($(Gcc)!0.5!(Javac)$);
\node[format,below of=Middle] (Exec) {Executable program};
\draw[->] (Heptagon) -- (Heptc);
\draw[->] (Heptc) -- node[right]{\texttt{-target ctrln}} (Ctrln);
\draw[->] (Ctrln) -- (ReaX);
\draw[->] (ReaX) -- node[right]{\texttt{--triang}} (Controller);
\draw[->] (Controller) -- (Ctrl2ept);
\draw[->] (Ctrl2ept) -- (HeptagonCtrlr);
\draw[->] (HeptagonCtrlr) -- (HeptcCtrlr);
\draw[->] (HeptcCtrlr) -- (C);
\draw[->] (C) -- (Gcc);
\draw[->] (Gcc) -- (Exec);
\coordinate (A) at ($(C) + (-3,3)$);
\draw[->] (Heptc) -| node[left,pos=0.75]{\texttt{-target c}} (A) -- (C);
\coordinate (B) at ($(Java) + (3,3)$);
\draw[->] (Heptc) -| node[right,pos=0.75]{\texttt{-target java}} (B) -- (Java);
\draw[->] (HeptcCtrlr) -- (Java);
\draw[->] (Java) -- (Javac);
\draw[->] (Javac) -- (Exec);
\end{tikzpicture}
\caption{BZReaX full compilation chain}
\label{fig:bzreax-compil}
\end{figure}
The Heptagon compiler is usually used to generate target code in a
general-purpose language, like C (option \texttt{-target c}) or Java
(option \texttt{-target java}). This generated code is composed of two
functions for each Heptagon:
\begin{itemize}
\item a \emph{reset} function, used to reset the node's state ;
\item a \emph{step} function, which takes as input the current inputs
of the node, update the current state, and computes the current
outputs.
\end{itemize}
If a node is provided with a contract, then the ReaX
verification/synthesis tool can be used. The Heptagon backend towards
Ctrl-n equations (input format for ReaX) is activated with the
\texttt{-target ctrln} option.
The ReaX tool can then be used to synthesize (generate automatically)
a controller which, composed with the initial program, will give
values to the controllable variables so that the ``enforce'' property
stated by the contract is verified.
This controller is initially a Boolean predicate, over the values of
inputs, current state and controllable variable. The ReaX option
\texttt{-triang} allows the obtention of a function (in the same
Ctrl-n input format), giving values to the controllable variables,
functions of values of current inputs and state.
This controller function can then be translated into an Heptagon node
by the \texttt{ctrl2ept} tool. This Heptagon node is composed in
parallel with the initial one, by the technical mean of a node
instanciation. Thus, the generated code of this controller can be
compiled and linked with the code generated from the initial Heptagon
program.
\section{Verification of logico-numerical Heptagon programs with ReaX}
Heptagon/BZR contracts can be used, with the ReaX tool, to verify
logico-numerical programs.
Let us look back at the example given in
Figure~\ref{fig:exple-contract}, and name this program Modes (in a
file named \texttt{modes.ept}).
\begin{lstlisting}
node twomodes (v:int) = (y:int)
contract
assume (v <= 1) & (v >= 0)
enforce (o <= 10) & (o >= 0)
var last x : int = 0;
let
y = x;
automaton
state Up
do x = last x + v
until x >= 10 then Down
state Down
do x = last x - v
until x <= 0 then Up
end
tel
\end{lstlisting}
We now want to check that the property stated by the contract is
guaranteed by the program. We begin then by compiling this program
towards the Ctrl-n input format :
\begin{alltt}
\textcolor{deepgreen}{> heptc -target ctrln modes.ept}
\end{alltt}
We obtain then a Ctrl-n program placed in a file named
\texttt{modes\_ctrln/twomodes.ctrln}. This file can be given as input
to the ReaX tool:
\begin{alltt}
\textcolor{deepgreen}{> reax -a 'sS:d=\{P:D\}' modes_ctrln/twomodes.ctrln}
[0.008 I Main] Reading node from `modes_ctrln/twomodes.ctrln'…
[0.024 I Supra] Variables(bool/num): state=(4/2), i=(0/1), u=(0/1), c=(0/0)
[0.024 I Df2cf] Preprocessing: discrete program
[0.024 I Verif] Forcing selection of power domain.
[0.024 I Synth] logico-numerical synthesis with powerset extension of power
domain over strict convex polyhedra with BDDs:
[0.068 I sB] Building controller…
[0.072 I sB] Computing boundary transtions…
[0.072 I sB] Simplifying controller…
[0.072 I Synth] {\color{red}logico-numerical synthesis with powerset extension of power
domain over strict convex polyhedra with BDDs succeeded.}
[0.072 I Main] Extracting generated controller…
[0.072 I Main] Checking generated controller…
[0.072 I Main] Outputting into `modes_ctrln/twomodes.ctrlr'…
\end{alltt}
The option \texttt{-a} followed by the string \verb+'sS:d={P:D}'+
defines the algorithme used for the verification. The algorithms
available are:
\begin{itemize}
\item \verb+'sB'+ for Boolean verification/synthesis (for Boolean
programs, or whose Boolean abstraction is meaningful)
\item \verb+'sS'+ for verification/synthesis using abstract
interpretation (over-approximation). The option \verb+'d={...}'+
allows the selection of abstract domains :
\begin{itemize}
\item \texttt{I} selects the domain of \emph{intervals}, for
programs with comparisons or operations between variables and
constants ;
\item \texttt{P} selects the domain of \emph{convex polyhedra},
suitable for programs with comparisons or simple operations (sum or
difference)
between variables.
\end{itemize}
The second part (\texttt{\ldots:D}) of this string selects the
\emph{powerset extension} of the power domain over the abstract
domain, suitable for programs with mixed Boolean, modes and
numerical operations on modes.
\end{itemize}
Our program involves operation between a state variable and an input
(\lstinline{last x + v}); thus we need to use the convex polyhedra
domain. Using a less precise domain such as intervals would lead to a
failed verification:
\begin{alltt}
\textcolor{deepgreen}{> reax -a 'sS:d={I:D}' modes_ctrln/twomodes.ctrln}
[0.012 I Main] Reading node from `modes_ctrln/twomodes.ctrln'…
[0.024 I Supra] Variables(bool/num): state=(4/2), i=(0/1), u=(0/1), c=(0/0)
[0.024 I Df2cf] Preprocessing: discrete program
[0.024 I Verif] Forcing selection of power domain.
[0.025 I Synth] logico-numerical synthesis with powerset extension of power
domain over intervals with BDDs:
[0.033 I Synth] {\color{red}logico-numerical synthesis with powerset extension of power
domain over intervals with BDDs failed.}
\end{alltt}
\section{Controller synthesis on logico-numerical Heptagon programs with ReaX}
We add now a controllable variable to our \texttt{twomodes} node. This
controllable variable \texttt{c} will be used to control the
transition between the two modes:
\begin{lstlisting}
node twomodes (v:int) = (y:int)
contract
assume (v <= 1) & (v >= 0)
enforce (o <= 10) & (o >= 0)
with (c:bool)
var last x : int = 0;
let
y = x;
automaton
state Up
do x = last x + v
until not c then Down
state Down
do x = last x - v
until not c then Up
end
tel
\end{lstlisting}
The transition between \texttt{Up} and \texttt{Down} is no longer
defined as a condition on the current value of \texttt{x}, but
controlled by the controller, via the given value of \texttt{c}.
The full compilation of this program consists in:
\begin{enumerate}
\item Heptagon compilation towards C code and Ctrl-n equations; the
\texttt{-s} option selects the simulated node (\texttt{twomodes})
\begin{alltt}
\textcolor{deepgreen}{> heptc -hepts -s twomodes -target c -target ctrln modes.ept}
\end{alltt}
\item Controller synthesis with ReaX (\texttt{--triang} option to
obtain a function)
\begin{alltt}
\textcolor{deepgreen}{> reax -a 'sS:d=\{P:D\}' --triang modes_ctrln/twomodes.ctrln}
[0.008 I Main] Reading node from `modes_ctrln/twomodes.ctrln'…
[0.024 I Supra] Variables(bool/num): state=(4/2), i=(1/1), u=(0/1), c=(1/0)
[0.024 I Df2cf] Preprocessing: discrete program
[0.024 I Verif] Forcing selection of power domain.
[0.024 I Synth] logico-numerical synthesis with powerset extension of power
domain over strict convex polyhedra with BDDs:
[0.072 I sB] Building controller…
[0.072 I sB] Computing boundary transtions…
[0.072 I sB] Simplifying controller…
[0.072 I Synth] logico-numerical synthesis with powerset extension of power
domain over strict convex polyhedra with BDDs succeeded.
[0.092 I t.] Triangulation…ng…
[0.092 I Main] Extracting triangularized controller…
[0.092 I Main] Checking triangularized controller…
[0.092 I Main] Splitting triangularized controller…
[0.092 I Main] Extracting split triangularized controller…
[0.092 I Main] Checking split triangularized controller…
[0.092 I Main] Outputting into `modes_ctrln/twomodes.0.ctrls'…
\end{alltt}
\item Translation of the controller towards Heptagon
\begin{alltt}
\textcolor{deepgreen}{> ctrl2ept -n Modes.twomodes}
\end{alltt}
\item Compilation of the controller towards C
\begin{alltt}
\textcolor{deepgreen}{> heptc -target c modes_controller.ept}
\end{alltt}
\item Compilation and linking of all C files, obtaining an executable
file for the simulation
\begin{alltt}
\textcolor{deepgreen}{> gcc -o sim -I/usr/local/lib/heptagon/c -Imodes_c -Imodes_controller_c
modes_c/_main.c modes_c/modes.c modes_c/modes_types.c
modes_controller_c/modes_controller.c
modes_controller_c/modes_controller_types.c}
\end{alltt}
\end{enumerate}
The program can then be simulated:\\
\begin{tikztimingtable}
v & 2D{0} 4D{1} 2D{0} 8D{1} 3D{0} 10D{1} \\
twomodes(v) & 2D{0}D{1}D{2}D{3} 3D{4}D{5}D{6}D{7}D{8}D{9}D{10}D{9} 4D{8}D{7}D{6}D{5}D{4}D{3}D{2}D{1}D{0}D{1}D{2} \\
\end{tikztimingtable}
\section{Encapsulation: the BZReaX script}
The full compilation chain described in the previous section has been
encapsulated into a script named \texttt{bzreax}, whose scope is
described in Figure~\ref{fig:bzreax}.
\begin{figure}
\centering
\pgfdeclarelayer{background}
\pgfsetlayers{background,main}
\begin{tikzpicture}[node distance=2cm]
\node[format] (Heptagon) {\begin{tabular}{c}Heptagon\\\texttt{.ept}\end{tabular}};
\node[tool,below of=Heptagon] (Heptc) {\begin{tabular}{c}Heptagon compiler\\\texttt{heptc}\end{tabular}};
\node[format,below of=Heptc] (Ctrln) {\begin{tabular}{c}Ctrl-n equations\\\texttt{.ctrln}\end{tabular}};
\node[tool,below of=Ctrln] (ReaX) {\begin{tabular}{c}ReaX synthesis tool\\\texttt{reax}\end{tabular}};
\node[format,below of=ReaX] (Controller) {\begin{tabular}{c}Controller function\\\texttt{.ctrlf}\end{tabular}};
\node[tool,below of=Controller] (Ctrl2ept) {\begin{tabular}{c}Controller compiler\\\texttt{ctrl2ept}\end{tabular}};
\node[format,below of=Ctrl2ept] (HeptagonCtrlr) {\begin{tabular}{c}Heptagon\\\texttt{.ept}\end{tabular}};
\node[tool,below of=HeptagonCtrlr] (HeptcCtrlr) {\begin{tabular}{c}Heptagon compiler\\\texttt{heptc}\end{tabular}};
\node[format,below left of=HeptcCtrlr,node distance=3cm] (C) {\begin{tabular}{c}C program\\\texttt{.c}\end{tabular}};
\node[format,below right of=HeptcCtrlr,node distance=3cm] (Java) {\begin{tabular}{c}Java program\\\texttt{.java}\end{tabular}};
\node[tool,below of=C] (Gcc) {\begin{tabular}{c}C compiler\\\texttt{gcc}\end{tabular}};
\node[tool,below of=Java] (Javac) {\begin{tabular}{c}Java compiler\\\texttt{javac}\end{tabular}};
\coordinate (Middle) at ($(Gcc)!0.5!(Javac)$);
\node[format,below of=Middle] (Exec) {Executable program};
\draw[->] (Heptagon) -- (Heptc);
\draw[->] (Heptc) -- node[right]{\texttt{-target ctrln}} (Ctrln);
\draw[->] (Ctrln) -- (ReaX);
\draw[->] (ReaX) -- node[right]{\texttt{--triang}} (Controller);
\draw[->] (Controller) -- (Ctrl2ept);
\draw[->] (Ctrl2ept) -- (HeptagonCtrlr);
\draw[->] (HeptagonCtrlr) -- (HeptcCtrlr);
\draw[->] (HeptcCtrlr) -- (C);
\draw[->] (C) -- (Gcc);
\draw[->] (Gcc) -- (Exec);
\coordinate (A) at ($(C) + (-3,3)$);
\draw[->] (Heptc) -| node[left,pos=0.75]{\texttt{-target c}} (A) -- (C);
\coordinate (B) at ($(Java) + (3,3)$);
\draw[->] (Heptc) -| node[right,pos=0.75]{\texttt{-target java}} (B) -- (Java);
\draw[->] (HeptcCtrlr) -- (Java);
\draw[->] (Java) -- (Javac);
\draw[->] (Javac) -- (Exec);
\begin{pgfonlayer}{background}
\path[fill=yellow!40,draw=deepyellow]
($(Heptc.north west) + (-0.5,0.5)$)
-- ($(Heptc.north east) + (0.5,0.5)$)
-- ($(HeptcCtrlr.south east) + (0.5,-0.5)$)
-- ($(C.north east) + (0.5,0.5)$)
-- ($(Gcc.south east) + (0.5,-0.5)$)
-- ($(Gcc.south west) + (-0.5,-0.5)$)
-- ($(C.north west) + (-0.5,0.5)$)
|- cycle;
\end{pgfonlayer}
\node[anchor=north west,color=deepyellow] at ($(Heptc.north west) + (-2,0.5)$) {\texttt{bzreax}};
\end{tikzpicture}
\caption{BZReaX script}
\label{fig:bzreax}
\end{figure}
Thus, the full compilation of the program described in pthe previous
section can be obtained by:
\begin{alltt}
\textcolor{deepgreen}{> bzreax modes.ept twomodes -a 'sS:d=\{P:D\}' -s}
[0.008 I Main] Reading node from `modes_ctrln/twomodes.ctrln'…
[0.020 I Supra] Variables(bool/num): state=(4/2), i=(1/1), u=(0/1), c=(1/0)
[0.020 I Df2cf] Preprocessing: discrete program
[0.020 I Verif] Forcing selection of power domain.
[0.020 I Synth] logico-numerical synthesis with powerset extension of power
domain over strict convex polyhedra with BDDs:
[0.056 I sB] Building controller…
[0.060 I sB] Computing boundary transtions…
[0.060 I sB] Simplifying controller…
[0.060 I Synth] logico-numerical synthesis with powerset extension of power
domain over strict convex polyhedra with BDDs succeeded.
[0.072 I t.] Triangulation…ng…
[0.072 I Main] Extracting triangularized controller…
[0.072 I Main] Checking triangularized controller…
[0.072 I Main] Splitting triangularized controller…
[0.072 I Main] Extracting split triangularized controller…
[0.072 I Main] Checking split triangularized controller…
[0.072 I Main] Outputting into `modes_ctrln/twomodes.0.ctrls'…
Info: Loading module of controllers for node Modes.twomodes…
Info: Reading function from `modes_ctrln/twomodes.0.ctrls'…
Info: Outputting into `modes_controller.ept'…
Info: To launch the simulator, run: `hepts -mod Modes -node twomodes -exec ./sim'
\end{alltt}
\bibliographystyle{plain}
\bibliography{manual}
\end{document}