Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
(* ========================================================================= *)
(* LTL decision procedure based on reduction to fair CTL model checking. *)
(* *)
(* Basically follows Clarke et al's "Another look at LTL model checking" *)
(* paper, though it's presented in a somewhat different style. *)
(* *)
(* Copyright (c) 2003, John Harrison. (See "LICENSE.txt" for details.) *)
(* ========================================================================= *)
(* ------------------------------------------------------------------------- *)
(* Prime all propositional variables in a term to perform "next" op. *)
(* ------------------------------------------------------------------------- *)
let next fm =
let ifn p = p |-> Atom(P(pname p^"'")) in
propsubst (itlist ifn (atoms fm) undefined) fm;;
(* ------------------------------------------------------------------------- *)
(* Transform the formula to fair CTL model checking. *)
(* ------------------------------------------------------------------------- *)
let rec ltl (fm,defs,fcs,n as quad) =
match fm with
Nott(p) -> let p',defs',fcs',n' = ltl(p,defs,fcs,n) in
Not(p'),defs',fcs',n'
| Andt(p,q) -> ltl2 (fun (p,q) -> And(p,q)) (p,q) quad
| Ort(p,q) -> ltl2 (fun (p,q) -> Or(p,q)) (p,q) quad
| Impt(p,q) -> ltl2 (fun (p,q) -> Imp(p,q)) (p,q) quad
| Ifft(p,q) -> ltl2 (fun (p,q) -> Iff(p,q)) (p,q) quad
| Next(p) -> ltl1 p (fun p v -> next p) (fun p v -> []) quad
| Box(p) ->
ltl1 p (fun p v -> And(p,next v)) (fun p v -> [Imp(p,v)]) quad
| Diamond(p) ->
ltl1 p (fun p v -> Or(p,next v)) (fun p v -> [Imp(v,p)]) quad
| Falset -> False,defs,fcs,n
| Truet -> True,defs,fcs,n
| Propvart(p) -> Atom(P p),defs,fcs,n
and ltl1 p cons1 cons2 (fm,defs,fcs,n) =
let p',defs',fcs',n' = ltl(p,defs,fcs,n) in
let v,n'' = mkprop n' in
v,(Iff(v,cons1 p' v)::defs'),(cons2 p' v @ fcs'),(n' +/ Int 1)
and ltl2 cons (p,q) (fm,defs,fcs,n) =
let fm1,defs1,fcs1,n1 = ltl (p,defs,fcs,n) in
let fm2,defs2,fcs2,n2 = ltl (q,defs1,fcs1,n1) in
cons(fm1,fm2),defs2,fcs2,n2;;
(* ------------------------------------------------------------------------- *)
(* Iterator analogous to "overatoms" for propositional logic. *)
(* ------------------------------------------------------------------------- *)
let rec itpropt f fm a =
match fm with
Propvart(x) -> f x a
| Nott(p) | Next(p) | Box(p) | Diamond(p) -> itpropt f p a
| Andt(p,q) | Ort(p,q) | Impt(p,q) | Ifft(p,q) ->
itpropt f p (itpropt f q a)
| _ -> a;;
(* ------------------------------------------------------------------------- *)
(* Get propositional variables in a temporal formula. *)
(* ------------------------------------------------------------------------- *)
let propvarst fm = setify(itpropt (fun h t -> h::t) fm []);;
(* ------------------------------------------------------------------------- *)
(* We also need to avoid primed variables. *)
(* ------------------------------------------------------------------------- *)
let max_varindex' pfx =
let mkf = max_varindex pfx in
fun s n ->
if s = "" then n else
let n' = mkf s n and l = String.length s - 1 in
if String.sub s l 1 <> "'" then n' else mkf (String.sub s 0 l) n';;
(* ------------------------------------------------------------------------- *)
(* Make a variable name "p_n". *)
(* ------------------------------------------------------------------------- *)
let mkname n = "p_"^(string_of_num n);;
(* ------------------------------------------------------------------------- *)
(* Overall LTL decision procedure (we add box to make sure top is variable). *)
(* ------------------------------------------------------------------------- *)
let ltldecide fm =
let n = Int 1 +/ itpropt (max_varindex' "p_") fm (Int 0) in
let Atom(P p),defs,fcs,m = ltl(Box fm,[],[],n) in
let vars = propvarst fm @ map mkname (n---(m-/Int 1)) in
fair_model_check vars True (list_conj defs) (AG(Propvarc(p))) fcs;;
(* ------------------------------------------------------------------------- *)
(* Example. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
let fm = let p = Propvart "p" in Impt(Next(Box p),Diamond(p));;
ltldecide fm;;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* Alternative version moving p into the starting states. *)
(* ------------------------------------------------------------------------- *)
let ltldecide' fm =
let n = Int 1 +/ itpropt (max_varindex' "p_") fm (Int 0) in
let p,defs,fcs,m = ltl(fm,[],[],n) in
let vars = propvarst fm @ map mkname (n---(m-/Int 1)) in
fair_model_check vars (Not p) (list_conj defs) (Notc(EG(Truec))) fcs;;
(* ------------------------------------------------------------------------- *)
(* A parser, just to make testing nicer. *)
(* ------------------------------------------------------------------------- *)
let rec parse_tformula inp =
parse_right_infix "<=>" (fun (p,q) -> Ifft(p,q))
(parse_right_infix "==>" (fun (p,q) -> Impt(p,q))
(parse_right_infix "\\/" (fun (p,q) -> Ort(p,q))
(parse_right_infix "/\\" (fun (p,q) -> Andt(p,q))
parse_tunary))) inp
and parse_tunary inp =
match inp with
"~"::onp -> papply (fun e -> Nott(e)) (parse_tunary onp)
| "("::")"::onp -> papply (fun e -> Next(e)) (parse_tunary onp)
| "["::"]"::onp -> papply (fun e -> Box(e)) (parse_tunary onp)
| "<>"::onp -> papply (fun e -> Diamond(e)) (parse_tunary onp)
| _ -> parse_tatom inp
and parse_tatom inp =
match inp with
[] -> failwith "Expected an expression at end of input"
| "false"::toks -> Falset,toks
| "true"::toks -> Truet,toks
| "("::toks -> parse_bracketed parse_tformula ")" toks
| p::toks -> Propvart(p),toks;;
let parsel s =
let toks,rest = parse_tformula(lex(explode s)) in
if rest = [] then toks else failwith "Unparsed input";;
(* ------------------------------------------------------------------------- *)
(* Examples. *)
(* ------------------------------------------------------------------------- *)
let default_parser = parsel;;
START_INTERACTIVE;;
ltldecide << <>[]p ==> []<>()<>[]p >>;;
ltldecide' << [](p ==> ()p) ==> [](p ==> []p) >>;;
ltldecide' << []<>p ==> <>[]p >>;;
(* ------------------------------------------------------------------------- *)
(* Compare performances (and check results!) on test cases. *)
(* ------------------------------------------------------------------------- *)
let test fm =
let a = time ltldecide fm in
let a' = time ltldecide' fm in
if a = a' then a else failwith("*** Disparity");;
test << (()[]p ==> <>p) >>;;
test << [] (()([]p) ==> <>p) >>;;
test << <>p ==> ()<>p >>;;
test << ()<>p ==> <>p >>;;
test << <>[]p ==> <>[]p >>;;
test << <>[]p ==> []<>p >>;;
test << ()(p /\ q) <=> () p /\ () q >>;;
test << [](p /\ q) <=> [] p /\ [] q >>;;
test << <>(p /\ q) <=> <> p /\ <> q >>;;
test << <>(p /\ q) ==> <> p /\ <> q >>;;
test << [](p ==> ()p) ==> [](p ==> []p) >>;;
test << [](p ==> ()p) ==> p ==> []p >>;;
test << [](p ==> ()p) ==> []p >>;;
test << [](p ==> ()q) /\ [](q ==> ()p) ==> []<>p >>;;
test << [](p ==> ()q) /\ [](q ==> ()p) ==> <>p ==> []<>p >>;;
test << <>(<>p) <=> <>p >>;;
test << [][]p <=> []p >>;;
test << ()[]p <=> []()p >>;;
test << []p ==> <>p >>;;
test << []p ==> ()p >>;;
test << ()p ==> <>p >>;;
test << [](p ==> ()p) ==> ()p ==> p ==> [] p >>;;
test << ~[]p <=> <>(~p) >>;;
test << []p ==> p >>;;
test << [](p ==> []p) ==> (p <=> []p) >>;;
test << []([]p ==> []q) <=> []([]p ==> q) >>;;
test << <>[]p ==> ()()()()<>[]p >>;;
test << <>[]p ==> ()()()()()()()()()<>[]p >>;;
test << <>[]<>p ==> []<>p >>;;
test << <>[]<>p ==> []<>[]<>p >>;;
test << ()[]p ==> []p >>;;
END_INTERACTIVE;;