Package: metric-temporal-logic
A library for manipulating and evaluating metric temporal logic.Table of ContentsAboutInstallationUsagePython Operator APIPropositional logic (using python syntax)Modal Logic (using python syntax)String based APIPropositional logic (parse api)Modal Logic (parser api)Boolean EvaluationQuantitative Evaluate (Signal Temporal Logic)UtilitiesSimilar ProjectsCitingAboutPython library for working with Metric Temporal Logic (MTL). Metric
Temporal Logic is an extension of Linear Temporal Logic (LTL) for
specifying properties over time series (SeeAlur). Some practical examples are
given in the usage.InstallationIf you just need to usemetric-temporal-logic, you can just run:$ pip install metric-temporal-logicFor developers, note that this project uses thepoetrypython package/dependency
management tool. Please familarize yourself with it and then
run:$ poetry installUsageTo begin, we importmtl.importmtlThere aretwoAPIs for interacting with themtlmodule. Namely, one can specify the MTL expression using:Python Operators.Strings + The parse API.We begin with the Python Operator API:Python Operator APIPropositional logic (using python syntax)a,b=mtl.parse('a'),mtl.parse('b')phi0=~aphi1=a&bphi2=a|bphi3=a^bphi4=a.iff(b)phi5=a.implies(b)Modal Logic (using python syntax)a,b=mtl.parse('a'),mtl.parse('b')# Eventually `a` will hold.phi1=a.eventually()# `a & b` will always hold.phi2=(a&b).always()# `a` until `b`phi3=a.until(b)# `a` weak until `b`phi4=a.weak_until(b)# Whenever `a` holds, then `b` holds in the next two time units.phi5=(a.implies(b.eventually(lo=0,hi=2))).always()# We also support timed until.phi6=a.timed_until(b,lo=0,hi=2)# `a` holds in two time steps.phi7=a>>2String based APIPropositional logic (parse api)# - Lowercase strings denote atomic predicates.phi0=mtl.parse('atomicpred')# - infix operators need to be surrounded by parens.phi1=mtl.parse('((a & b & c) | d | e)')phi2=mtl.parse('(a -> b) & (~a -> c)')phi3=mtl.parse('(a -> b -> c)')phi4=mtl.parse('(a <-> b <-> c)')phi5=mtl.parse('(x ^ y ^ z)')# - Unary operators (negation)phi6=mtl.parse('~a')phi7=mtl.parse('~(a)')Modal Logic (parser api)# Eventually `x` will hold.phi1=mtl.parse('F x')# `x & y` will always hold.phi2=mtl.parse('G(x & y)')# `x` holds until `y` holds.# Note that since `U` is binary, it requires parens.phi3=mtl.parse('(x U y)')# Weak until (`y` never has to hold).phi4=mtl.parse('(x W y)')# Whenever `x` holds, then `y` holds in the next two time units.phi5=mtl.parse('G(x -> F[0, 2] y)')# We also support timed until.phi6=mtl.parse('(a U[0, 2] b)')# Finally, if time is discretized, we also support the next operator.# Thus, LTL can also be modeled.# `a` holds in two time steps.phi7=mtl.parse('XX a')Quantitative Evaluate (Signal Temporal Logic)Given a propertyphi, one can evaluate if a timeseries satisifiesphi. Time Series can either be defined using a dictionary mapping
atomic predicate names to lists of (time,val) pairsorusing
theDiscreteSignalsAPI (used internally).There are two types of evaluation. One uses the boolean semantics of
MTL and the other uses Signal Temporal Logic like semantics.# Assumes piece wise constant interpolation.data={'a':[(0,100),(1,-1),(3,-2)],'b':[(0,20),(0.2,2),(4,-10)]}phi=mtl.parse('F(a | b)')print(phi(data))# output: 100# Evaluate at t=3print(phi(data,time=3))# output: 2# Evaluate with discrete timephi=mtl.parse('X b')print(phi(data,dt=0.2))# output: 2Boolean EvaluationTo Boolean semantics can be thought of as a special case of the
quantitative semantics whereTrue ↦ 1andFalse ↦ -1.  This
conversion happens automatically using thequantitative=Falseflag.# Assumes piece wise constant interpolation.data={'a':[(0,True),(1,False),(3,False)],'b':[(0,False),(0.2,True),(4,False)]}phi=mtl.parse('F(a | b)')print(phi(data,quantitative=False))# output: Truephi=mtl.parse('F(a | b)')print(phi(data))# output: True# Note, quantitative parameter defaults to False# Evaluate at t=3.print(phi(data,time=3,quantitative=False))# output: False# Compute sliding satisifaction.print(phi(data,time=None,quantitative=False))# output: [(0, True), (0.2, True), (4, False)]# Evaluate with discrete timephi=mtl.parse('X b')print(phi(data,dt=0.2,quantitative=False))# output: TrueUtilitiesimportmtlfrommtlimportutilsprint(utils.scope(mtl.parse('XX a'),dt=0.1))# output: 0.2print(utils.discretize(mtl.parse('F[0, 0.2] a'),dt=0.1))# output: (a | X a | XX a)Similar ProjectsFeel free to open up a pull-request to add other similar projects. This library was written to meet some of my unique needs, for example I wanted the AST to be immutable and wanted the library tojusthandle manipulating MTL. Many other similar projects exist with different goals.https://github.com/doganulus/python-monitorshttps://github.com/STLInspector/STLInspectorCiting@misc{pyMTL,
  author       = {Marcell Vazquez-Chanlatte},
  title        = {mvcisback/py-metric-temporal-logic: v0.1.1},
  month        = jan,
  year         = 2019,
  doi          = {10.5281/zenodo.2548862},
  url          = {https://doi.org/10.5281/zenodo.2548862}
}