- 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, STLspec = 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")
# TrueThen, 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 valueThe 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.robustnessWe 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.objas 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 usingstltestcommand 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
~/.pylintrcwith the following contentNote that please replace[MASTER] init-hook='import sys; sys.path.append("/path/to/STL-API")'/path/to/STL-APIwith 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 2possible 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