In this section we introduce syntax and semantics of the minimal core of TeSSLa. In examples we use parametrized definitions, e.g. \(\mathbf {merge}(x, y) := \ldots \) on top, which are expanded to their definitions until only core operators remain.
Preliminaries. Given a partial order \((A, \le )\), a set \(D \subseteq A\) is called directed if \(\forall a, b \in D: a \le b \vee b \le a\). \((A, \le )\) is called directed-complete partial order (dcpo) if there exists a supremum \(\bigvee D\) for every directed subset \(D \subseteq A\). Let \(f \in A \rightarrow B\) be a function and \((A, \le )\), \((B, \le ')\) partial orders. f is called monotonic if it preserves the order, i.e. \(\forall a_1, a_2 \in A: a_1 \le a_2 \Rightarrow f(a_1) \le ' f(a_2)\). f is called continuous if it preserves the supremum, i.e. \(\bigvee f(D) = f(\bigvee ' D)\) for all directed subsets \(D \subseteq A\). By the Kleene fixed-point theorem, every monotonic and continuous function \(f: A \rightarrow A\) has a least fixed point \(\mu f\) if \((A, \le )\) is a dcpo with a least element \(\bot \). \(\mu f\) is the least upper bound of the chain iterating f starting with the bottom element: \(\mu f = \bigvee \{ f^n(\bot ) \mid n \in \mathbb N \}\).
Syntax. A TeSSLa specification \(\varphi \) consists of a set of possibly mutually recursive stream definitions defined over a finite set of variables \(\mathbb {V}\) where an equation has the form \(x := e\) with \(x \in \mathbb {V}\) and
$$ e \,{:}{:}{=}\, \mathbf {nil} ~|~ \mathbf {unit} ~|~ x ~|~ \mathbf {lift}(f)(e, \ldots , e) ~|~ \mathbf {time}(e)~|~ \mathbf {last}(e, e)~|~ \mathbf {delay}(e, e). $$
All variables not occuring on the left-hand side of equations are input variables. All variables on the left-hand side are output variables. We call a TeSSLa specification flat if it does not contain any nested expressions. Every specification can be represented as a flat specification by using additional variables and equations.
Semantics. We define the semantics of TeSSLa in terms of an abstract time domain which only requires a total order and corresponding arithmetic operators:
Definition 1
A time domain is a totally ordered semi-ring \((\mathbb {T},0,1,+,\cdot , \le )\) that is not negative, i.e. \(\forall _{t \in \mathbb {T}}\, 0 \le t\).
We extend the order on time domains to the set \(\mathbb {T}_{\infty } = \mathbb {T} \cup \{\infty \}\) with \(\forall _{t \in \mathbb {T}}\, t < \infty \).
Conceptually, streams are timed words that are known inclusively or exclusively up to a certain timestamp, its progress, that might be infinite. A stream might contain an infinite number of events even if its progress is finite.
Definition 2
An event stream over a time domain \(\mathbb {T}\) and a data domain \(\mathbb {D}\) is a finite or infinite sequence \(s = a_0 a_1 \dots \in \mathcal {S}_{\mathbb {D}} = (\mathbb {T} \cdot \mathbb {D})^{\omega } \cup (\mathbb {T} \cdot \mathbb {D})^+ \cup (\mathbb {T} \cdot \mathbb {D})^* \cdot (\mathbb {T}_{\infty } \mathbb {T} \cdot \{\bot \})\) where \(a_{2i} < a_{2(i+1)}\) for all i with \(0<2(i+1)<|s|\) (|s| is \(\infty \) for infinite streams). The prefix relation over \({\mathcal {S}}_{\mathbb {D}}\) is the least relation that satisfies \(s \sqsubseteq s\), \(u \sqsubseteq s\) if \(uv \sqsubseteq s\) and \(ut'\bot \sqsubseteq s\) if \(ut \sqsubseteq s\), \(t' < t, t \in \mathbb {T}_{\infty }\) and \(t' \in \mathbb {T}\).
We say a stream has an event with value d at time t if in its sequence d directly follows t. We say a stream is known at time t if it contains a strictly larger timestamp or a non-strictly larger timestamp followed by a data value or \(\bot \). Where convenient, we also see streams as functions \(s \in \mathbb {T} \rightarrow \mathbb {D} \cup \{\bot ,\mathrm {?}\}\) such that \(s(t) = d\) if the stream has value d at time \(t, s(t) = \bot \) if it is known to have no value, and \(s(t) = \mathrm {?}\) otherwise. We refer to the supremum of all known timestamps of a stream as inclusive or exclusive progress, depending on whether it is itself a known timestamp. The prefix relation realises the intuition of cutting a stream at a certain point in time while keeping or removing the cutting point.
In the following, we present the denotation of a specification \(\varphi \) as a function between input streams and output streams.
Definition 3 (TeSSLa semantics)
Given a specification \(\varphi \) of equations \(y_i := e_i\), every \(e_i\) can be interpreted as a function of input streams \(s_1, \ldots , s_k\) and output streams \(s'_{1}, \ldots , s'_{n}\), that is composed of the primitive functions whose denotation is given in the rest of this section. Input variables are mapped to input streams, \(\llbracket x_i \rrbracket _{s_1, \ldots , s_k, s'_{1}, \ldots , s'_{n}} = s_i\) and output variables to output streams, \(\llbracket y_i \rrbracket _{s_1, \ldots , s_k, s'_{1}, \ldots , s'_{n}} = s'_i\). Thus for fixed input streams \(s_1, \ldots , s_k\) and every \(e_i\), we obtain a function \(\llbracket e_i \rrbracket _{s_{1}, \ldots , s_{k}} \in \mathcal S_{\mathbb {D}'_{1}}\times \ldots \times \mathcal S_{\mathbb {D}'_{n}} \rightarrow \mathcal S_{\mathbb {D}'_{i}}\) and in combination a function \(\llbracket e_1,\ldots ,e_n \rrbracket _{s_{1}, \ldots , s_{k}} \in \mathcal S_{\mathbb {D}'_{1}}\times \ldots \times \mathcal S_{\mathbb {D}'_{n}} \rightarrow \mathcal S_{\mathbb {D}'_{1}}\times \ldots \times \mathcal S_{\mathbb {D}'_{n}}\). We now define the denotation of a specification \(\varphi \) as the least fixed-point of this function.
$$\begin{aligned} \llbracket \varphi \rrbracket&\in \mathcal S_{\mathbb {D}_{1}}\times \ldots \times \mathcal S_{\mathbb {D}_{k}} \rightarrow \mathcal S_{\mathbb {D}'_1}\times \ldots \times \mathcal S_{\mathbb {D}'_n}\\ \llbracket \varphi \rrbracket&(s_{1}, \ldots , s_{k}) = \mu \left( \llbracket e_1,\ldots ,e_n \rrbracket _{s_{1}, \ldots , s_{k}} \right) \end{aligned}$$
The function \(\llbracket e_1,\ldots ,e_n \rrbracket _{s_{1}, \ldots , s_{k}}\) is monotonic and continuous because all primitive TeSSLa functions defined later in this section are monotonic and continuous and both properties are closed under function composition and cartesian products. \((\mathcal {S}_{\mathbb {D}}, \sqsubseteq )\) and by extension \((\mathcal {S}_{\mathbb {D}_1} \times \ldots \times \mathcal {S}_{\mathbb {D}_n}, \sqsubseteq \times \ldots \sqsubseteq )\) are dcpos. By the Kleene fixed-point theorem \(\llbracket e_1,\ldots ,e_n \rrbracket _{s_{1}, \ldots , s_{k}}\) has a least fixed point, which is the least upper bound of its Kleene chain.
Next we give the semantics of the primitive TeSSLa functions. The dependency of the input and output streams \(s_{1}, \ldots , s_{k}, s'_1, ..., s'_n\) is assumed implicitly.
Definition 4
Nil is a constant for the completely known stream without any events: \(\llbracket \mathbf {unit} \rrbracket = \infty \in \mathcal {S}_{\mathbb {D}}\).
We use the unit type
for streams that can carry only the single value
.
Definition 5
Unit is a constant for the completely known stream with a single unit event at timestamp zero: 
The following functions are given by specifying two conditions: the first for positions where an output event occurs, and the second where no output event occurs. Thereby the progress of the stream is defined indirectly as the position where the output can no longer be inferred from these conditions.
Definition 6
The time operator returns the stream of the timestamps of another stream \(\llbracket \mathbf {time}(e) \rrbracket = \mathsf {time}(\llbracket e \rrbracket )\) where \(\mathsf {time} \in \mathcal {S}_{\mathbb {D}} \rightarrow \mathcal {S}_{\mathbb {T}}\) is defined as \(\mathsf {time}(s) = s'\) such that
$$ \forall _{t} s'(t) = t \Leftrightarrow s(t) \in \mathbb {D} \qquad \forall _{t} s'(t) = \bot \Leftrightarrow s(t) = \bot . $$
The lift operator lifts an n-ary function f from values to streams. The notation \(A_1 \times \ldots \times A_n \rightarrowtail B\) denotes the set of functions where all \(A_i\) and B have been extended by the value \(\bot \).
Definition 7
Unary lift is defined as \(\llbracket \mathbf {lift}(f)(e) \rrbracket = \mathsf {lift_1}(f)(\llbracket e \rrbracket )\) where \(\mathsf {lift}_1 \in (\mathbb {D}\rightarrowtail \mathbb {D}') \rightarrow (\mathcal {S}_{\mathbb {D}} \rightarrow \mathcal {S}_{\mathbb {D}'})\) is given by \(\mathsf {lift}_1(f)(s) = s'\) such that
$$\begin{aligned} \forall _{t,d\in \mathbb {D}^{\prime }} s'(t) = d&\Leftrightarrow s(t) \in \mathbb {D} \wedge f(s(t)) = d\\ \forall _{t} s'(t) = \bot&\Leftrightarrow s(t) = \bot \vee s(t) \in f(s(t)) = \bot . \end{aligned}$$
Definition 8
Binary lift is given as \(\llbracket \mathbf {lift}(f)(e_1, e_2) \rrbracket = \mathsf {lift_2}(f)(\llbracket e_1 \rrbracket , \llbracket e_2 \rrbracket )\) where \(\mathsf {lift}_2 \in (\mathbb {D}_1 \times \mathbb {D}_2 \rightarrowtail \mathbb {D}') \rightarrow (\mathcal {S}_{\mathbb {D}_1} \times \mathcal {S}_{\mathbb {D}_2} \rightarrow \mathcal {S}_{\mathbb {D}'})\) is given by \(\mathsf {lift}_2(f)(s,s') = s''\) s.t.
where \(\mathsf {known}(t) := s(t) \ne \mathrm {?} \wedge s'(t) \ne \mathrm {?}\).
The binary lift can naturally be extended to an n-ary lift by recursively combining two streams into a stream of tuples or partially applied functions until the final result is obtained. Alternatively, the scheme of the binary lift can be easily extended to higher arities.
Example 1
Merge combines events of two streams, prioritising the first one.
Example 2
Const maps the values of all events of the input stream to a constant value: \(\mathbf {const}(c)(a) := \mathbf {lift}(\mathsf {constaux}(c))(a)\) with \(\mathsf {constaux}(c)(a) := c\). Using \(\mathbf {const}\) we can lift constants into streams representing a constant signal with this value, e.g. \(\mathbf {true} := \mathbf {const}({\text {true}})(\mathbf {unit})\) or \(\mathbf {zero} := \mathbf {const}(0)(\mathbf {unit})\).
Definition 9
The last operator takes two streams and returns the previous value of the first stream at the timestamps of the second. It is defined as \(\llbracket \mathbf {last}(e_1, e_2) \rrbracket = \mathsf {last}(\llbracket e_1 \rrbracket , \llbracket e_2 \rrbracket )\) where \(\mathsf {last}_{\mathbb {D},\mathbb {D}'} \in \mathcal {S}_{\mathbb {D}} \times \mathcal {S}_{\mathbb {D}'} \rightarrow \mathcal {S}_{\mathbb {D}}\) is given as \(\mathsf {last}(s, s') = s''\) such that
where \(\mathsf {noData}(t, t') := \forall _{t'' | t< t'' < t'} s(t'') = \bot \) and \(\mathsf {defined}(t) := \forall _{t' < t} s''(t')\ne \mathrm {?}\).
Note that while TeSSLa is defined on event streams, last realizes some essential aspects of the signal semantics: With this operator one can query the last known value of an event stream at a specific time and hence interpret the events on this stream as points where a piece-wise constant signal changes its value.
Example 3
By combining the \(\mathbf {last}\) and the \(\mathbf {lift}\) operators, we can now realize the signal lift semantics implicitly used in the introduction:
\(\mathbf {slift}(f)(x, y) := \mathbf {lift}(\mathsf {sliftaux}(f))(x',y')\) with
Example 4
In order to filter an event stream with a dynamic condition, we apply the last known filter condition to the current event:
\(\mathbf {filter}(z, x) := \mathbf {lift}(\mathsf {filteraux})(\mathbf {merge}(z, \mathbf {last}(z, x)), x)\)
Definition 10
The delay operator takes delays as its first argument. After a delay has passed, a unit event is emitted. A delay can only be set if a reset event is received via the second argument, or if an event is emitted on the output. Formally, \(\llbracket \mathbf {delay}(e_1, e_2) \rrbracket = \mathsf {delay}(\llbracket e_1 \rrbracket , \llbracket e_2 \rrbracket )\) where \(\mathsf {delay}_{\mathbb {D}} \in \mathcal {S}_{\mathbb {T}\backslash \{0\}} \times \mathcal {S}_{\mathbb {D}} \rightarrow \mathcal {S}_{\mathbb {U}}\) is given as \(\mathsf {delay}(s, s') = s''\) such that
where
, \(\mathsf {unsetable}(t) := s''(t) = \bot \wedge s'(t) = \bot \), \(\mathsf {noreset}(t, t') := \forall _{t'' | t< t'' < t'} s'(t'') = \bot \) and \(\mathsf {reset}(t, t') := \exists _{t'' | t< t'' < t'} s'(t'') \in \mathbb {D}\).
In many applications the delay operator is used in simplified versions: In the first example of the introduction that uses the delay operator, the delay and the reset argument can be the same because the delay is used only in non-recursive equations and every new delay is a reset, too. If a periodical event pattern is generated independently from input events then the second argument can be set to unit because only an initial reset event is needed. The full complexity of the delay operator is only needed if the delay is used in recursive equations with input dependencies and ensures that the fixed-point is unique.
We can observe that all basic functions are monotonic and continuous. From the fact, that these properties are closed under composition and the smallest fixed-point is determined by the Kleene chain, we can therefore conclude:
Proposition 1
The semantics of a TeSSLa specification is monotonic and continuous in the input streams.
In other words, the semantics will provide an extended result for an extended input and is therefore suited for online monitoring.
We can further observe that the pre-fixed-points on the Kleene chain have the following property: the progress only increases a finite number of times until a further event has to be appended. This is due to the basic functions that do handle progress in this way. We therefore obtain:
Theorem 1
For a specification \(\varphi \) every finite prefix of \(\llbracket \varphi \rrbracket (s_1, \ldots , s_k)\) can be computed assuming all lifted functions are computable. Assuming they are computable in O(1) steps, the prefix can be computed in \(O(k\cdot |\varphi |)\) steps where k is the number of events over all involved streams.
Note that in case the specification contains no \(\mathbf {delay}\) output streams cannot contain any such timestamps that did not occur already in the inputs. Further note, that fixed-points might contain infinitely many positions with data values (in case of \(\mathbf {delay}\)) and we can thus only compute prefixes. A respective monitor would exhibit infinite outputs even for finite inputs.
Due to Proposition 1 we can reuse a previously computed fixed-point if new input events occur and hence also compute the outputs incrementally.
Well-Formedness. While the least fixed-point is unique it does not have to be the only fixed-point. In that case, the least fixed-point is often the stream with progress 0 or some other stream with too little progress and one would be interested in (one of) the maximal fixed-points. Since the largest fixed-points would be more difficult to compute, especially in the setting of online monitoring, we define a fragment for which a unique fixed-point exists.
Definition 11
We call a TeSSLa specification \(\varphi \) well-formed if every cycle of the dependency graph (of the flattened specification) contains at least one delayed-labelled edge. The dependency graph of a flat TeSSLa specification \(\varphi \) of equations \(y_i := e_i\) is the directed multi-graph \(G = (V,E)\) of nodes \(V = \{y_1, \ldots , y_n\}\). For every \(y_i := e_i\) the graph contains the edge \((y_i, y_j)\) iff \(y_j\) is used in \(e_i\). We label edges corresponding to the first argument of \(\mathbf {last}\) or \(\mathbf {delay}\) with delayed.
Theorem 2
Given a well-formed specification \(\varphi \) of equations \(y_i := e_i\) and input streams \(s_1, \ldots , s_k\) then \(\mu (\llbracket e_1, \ldots , e_n \rrbracket _{s_{1}, \ldots , s_{k}})\) is the only fixed-point.
Proof
From the Kleene fixed-point theorem we know \(\mu \left( \llbracket e_1, \ldots , e_n \rrbracket _{s_{1}, \ldots , s_{k}} \right) = \bigsqcup \{ \llbracket e_1, \ldots , e_n \rrbracket ^n_{s_{1}, \ldots , s_{k}}(\bot ) \mid n \in \mathbb N \}\). Because \(\varphi \) is well-formed, every \(\llbracket e_i \rrbracket _{s_{1}, \ldots , s_{k}}\) is either constant or contains at least one \(\mathbf {last}\) or \(\mathbf {delay}\). The input streams \(s_{1}, \ldots , s_{k}\) limit progress, i.e. the maximal timestamp produced, of \(\llbracket e_i \rrbracket _{s_{1}, \ldots , s_{k}}\). The progress strictly increases with every step of the iteration of \(\llbracket e_1,\ldots ,e_n \rrbracket _{s_{1}, \ldots , s_{k}}\) in the Kleene chain until the limit given by the input streams is reached. Every other fixed-point of \(\llbracket e_1,\ldots ,e_n \rrbracket _{s_{1}, \ldots , s_{k}}\) must be an extension of the least fixed-point, but the least fixed-point has already the maximal progress permitted by the input streams. \(\square \)