- STL API
STL API is used to evaluate Signal Temporal Logic specification with respect to an arbitrary signal.
export PATH="/path/to/STL-API/bin/directory:$PATH"
-
Temporary Solution:
import sys sys.path.append("/path/to/STL-API/directory/") import stl.api
-
Permanent Solution:
Adding the following line to your shell configuration file (in Unix-based OS). For Mac users, the default shell configuration file is ~/.zshrc
export PYTHONPATH="/path/to/STL-API/directory:$PYTHONPATH"
export STLPATH="/path/to/STL-API/"
finally, execute the following command on the command line to reload .zshrc
zsh configuration file
source ~/.zshrc
- Python3.9+
- rply (for parser and lexer)
- termcolor (for color printing tools)
- Evaluate simple mathematical expressions and propositional logic
- Calculate the robustness value of a signal with respect to an STL formula
- Syntactically weaken the STL formula
Below we will be showing a simple example demonstrating the usage of the STL API by evaluating a simple STL expression G[0, 1](x > y)
with respect to a signal
To begin, we have to import the essential libraries from the STL API
from stl import Signal, STL
spec = STL("1 + 1")
# 2
spec = STL("true => false")
# False
signal = Signal(py_dict={"0": {"content": {"x": 1, "y": 2}},
"1": {"content": {"x": 2, "y": 1}}})
spec = STL("x > 0")
# True
Then, we define a (global) start time in int
type, as well as defining an arbitrary signal
time_begin = 0
signal = Signal(py_dict={"0": {"content": {"x": 1, "y": 2}},
"1": {"content": {"x": 2, "y": 1}}})
Next, we define the STL expression we would like to evaluate
stl_spec = STL("G[0, 1](x > y)")
There are often two parameters that we can obtain from the evaluation of STL expressions, namely, the satisfaction value,
in bool
type (True/False), and the robustness value and the robustness value, in float
type. There are two ways
of accessing these values:
The first approach is a fairly straightforward one:
satisfy : bool = stl_spec.satisfy(time_begin, signal) # obtain the satisfaction value
robustness : float = stl_spec.robustness(time_begin, signal) # obtain the robustness value
The second approach is a bit less straightforward, but it allows the evaluation results to be cached for future access
within an object called Eval_Result
stl_eval: Eval_Result = stl_spec.eval(time_begin, signal)
satisfy : bool = stl_eval.satisfy
robustness : float = stl_eval.robustness
We can also use the Python API to weaken the constraint of an STL formula. For example, suppose we have an STL expression with the following form
stl_spec = STL("G[0, 1](0 < x < 1)")
One way of weakening the formula is by relaxing the bound of the atomic proposition in the STL formula
weakened_stl_spec_1 = stl_spec.weaken("ap-range", 2, 3)
print(weakened_stl_spec_1)
# G[0, 1]((0 - 2) < x < (1 + 3))
weakened_stl_spec_2 = stl_spec.weaken("time-range", 2, 3)
# G[0 - 2, 1 + 3](0 < x < 1)
We can simply the usage procedure above into a simply REPL interface. Users can start the REPL by typing stlinterp
on
the command line
$ stlinterp
Time Start: 0
Signal:
{
"0": {
"content": {
"x": 1,
"y": 2
}
},
"1": {
"content": {
"x": 2,
"y": 1
}
}
}
Please enter STL expressions to be interpreted.
>>>
Once the REPL is started, it will prompt you to enter the STL expression. Users can simply type the expression
G[0, 1](x > y)
after the >>>
, click Enter
to evaluate the expression.
>>> G[0, 1](x > y)
satisfy : False
robustness : -1.0
- API-level interfaces (high-level)
- They are designed to be simple to use with minimal overhead for training and learning.
- API-level interfaces include
stl.obj
as well as programs instl.api
.
- Low-level interfaces
- Low-level interfaces are designed to support lower-level operations like lexing and parsing of the strings passed in from the API level. It is not intended to interact with the user directly.
- It includes all modules in
stl.parsing
bin/
: consists of bash scripts. must be added to system PATH
variable to be executed on the command line.
stllex
: start the REPL for the lexical analyzerstlparse
: start the REPL for the parserstlinterp
: start the REPL for the interpreterstltest
: initiate unit teststlsize
: show the size of the codebase
code-style/
: consists of code-writing guidelines excerpted from Google for code consistency purposes (for developers of the repository)
example/
-> stl/example/
: demonstrate example usage of the internal helper functions, low-level structures (lexer and parser level) as well as high-level objects (api level)
stl/
: main code repository
api.py
: main entry point for importing high-level (api level) objects and functionstool.py
: foundational tools for code repositoryunit_test.py
: handle unit testing of objects and tools, can be invoked usingstltest
command on the command lineobj/
: imported byapi.py
, intended to be used by the users of the API. consists of API level objectsparsing/
: not intended to be used directly by the user. low-level (parser and lexer level objects, i.e. AST (abstract syntax tree), type signatures)error.py
: main entry point for importing errorserr/
: all definition/implementation of errors
- Vscode PyLint "Unable to Import" Error
- See Stackoverflow
- create
~/.pylintrc
with the following contentNote that please replace[MASTER] init-hook='import sys; sys.path.append("/path/to/STL-API")'
/path/to/STL-API
with the actual absolute path to the location of the respository
- example folder is in stl folder for unit-test purpose, a symbolic link for example folder is created in the project root directory
-
Fixed the bug when adding an integer to a floating-point number in stl interpreter
>>> 1 + 1.5 2
possible fix, detect type mismatch, and coerce all int types to float types
-
create numeric type instead of using Ints and Floats
- reduce type check effort and automatically convert Ints to Floats
-
syntax for absolute value
G[0, 1](|y| > 1)
means that the absolute value of y must be greater than 1 between time 0 and 1 of the signal
-
support for nested STL expression
F G[0, 10](y > 1)
means that between time 0 and time 10, the y parameter of the signal will eventually always be greater than 1
-
allow passing in external function/objects to evaluation
class Coord: def __init__(self, x, y): ... def distance_between_points(p1, p2) -> float: ... return result stl_spec = STL("G[0, 1](distance_between_points(Coord(a, b), Coord(c, d)) > 3)") stl_spec.add_extern_func(distance_between) stl_spec.add_extern_obj(Coord) stl_spec.eval(...)
-
improved the signal so that it can handle more continuous times
- signal = Signal(py_dict={"0": {"content": {"timestamp": 0.1, "x": 1}}, "1": {"content": {"timestamp": 0.2, "x": 2}}})
- when the signal has "timestamp" as a quantifiable key, the STL expressions will evaluate based upon the timestamp instead of the timeindex
- backward compatibility