module Field : sig ... end
module Variable : sig ... end
module Assignment : sig ... end
module Expression : sig ... end
type t
An LTL formula. Evaluates to true or false given a sequence of states and
an assignment of variables (written xs |= t, values
). Our solver finds all
satisfying assignments.
Some formulas are not defined on empty sequences. Validation will reject
such formulas along with formulas in which an argument of a next
operator is not defined on empty sequences - see validate
below for
details.
include sig ... end
val sexp_of_t : t ‑> Base.Sexp.t
val const : bool ‑> t
val eq : 'a Variable.t ‑> 'a Field.t ‑> t
Undefined on empty sequences.
x :: _ |= (eq v fld), values
if the state x
contains field fld
and
State.get fld x = Assignment.find_exn values v
.
In particular, the negation of this formula is true if a field does not exist.
val predicate : ?description:string ‑> bool Expression.t ‑> t
Undefined on empty sequences.
x :: _ |= (predicate p), values
if Expression.eval p x values
evaluates
to true
(the function Expression.eval
is not exposed in this mli).
Example:
let gt var fld =
predicate Expression.(map2 (variable var) (field fld) ~f:(>))
If expression evaluation produces failure (refers to a missing field), its value is considered false.
next a
means "the tail of the sequence satisfies a
". a
must be
defined on empty sequences.
next a
is false if the sequence is empty.
x :: xs |= (next a), values
if xs |= a, values
.
Because of behaviour on empty sequences next (negate a)
is not the same
as negate (next a)
.
until a b
means "b eventually happens, and a holds at all times until
that (non-inclusive)".
False on an empty sequence.
x :: xs |= (until a b), values
if
x :: xs |= b, values
or
(x :: xs |= a, values
and xs |= (until a b), values
)
You almost always want to use the special case eventually
(see
below).
release a b = negate (until (negate a) (negate b))
means
"b must hold until a happens (inclusive); if a never happens, b must hold forever."
True on an empty sequence.
x :: xs |= (release a b), values
if
x :: xs |= b, values
and
(x :: xs |= a, values
or xs |= (release a b), values
)
You almost always want to use the special case always
(see below).
val before : Core.Time_ns.t ‑> t
before t
is true if the state has time less or equal to t
. before t
is false if the time is None
.
val after : Core.Time_ns.t ‑> t
after t
is true if the state has time greater or equal to t
. after t
is false if the time is None
.
val before_var : ?add:Core.Time_ns.Span.t ‑> Core.Time_ns.t Variable.t ‑> t
before_var ~add v
is true if the state has time less or equal to
v + add
.
val after_var : ?add:Core.Time_ns.Span.t ‑> Core.Time_ns.t Variable.t ‑> t
after_var ~add v
is true if the state has time greater or equal to
v + add
.
field_predicate fld f
is a predicate that is true if the state contains
fld
and the value of fld
satisfies f
:
field_predicate fld f
= predicate Expression.(map ~f (field fld))
module O : sig ... end
val validate : t ‑> unit Core.Or_error.t
If validate
returns Ok
then so do eval
and query
. A formula may be
rejected for several reasons:
1 Its value is not defined for empty sequences. This is the case for
predicate
and eq
formulas that refer to the initial state of the
sequence. Validation requires that both in the top-level formula and in
the argument of each next
operator every predicate
or eq
occurs
underneath an until
or release
.
2 The solver cannot reorder the clauses such that each variable is
constrained by an equality before being used in an inequality
or a predicate. A subformula x != 12
is rejected, but a subformula
(x != 12) /\ (x == 12)
is accepted. See the top of the .ml file for
the description of the solving algorithm that goes into more detail.
Condition 2 guarantees that the set of all variable assignments that
satisfy the formula is explicit: it can be described as
complete(E1) U ... U complete(En)
where E1, ..., En
are variable assignments (possibly undefined for some
variables of the formula) and complete(E)
is the set of all assignments
that refine E
. This representation is returned by query
below.
val eval : ?debug:Async.Log.t ‑> ?allow_nonmonotonic_times:bool ‑> ?allow_missing_times:bool ‑> t ‑> State.t Async.Pipe.Reader.t ‑> bool Async.Deferred.t Core.Or_error.t
eval t input
returns true
if there exists an assignment E
such that
input |= t, E
.
val query : ?debug:Async.Log.t ‑> ?allow_nonmonotonic_times:bool ‑> ?allow_missing_times:bool ‑> t ‑> State.t Async.Pipe.Reader.t ‑> Assignment.t Async.Pipe.Reader.t Core.Or_error.t