1use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
6use std::collections::{HashMap, HashSet, VecDeque};
7
8use super::types::{
9 AbstractDomain, AbstractTransformer, AtomicProposition, BDDManager, BDDModelChecker,
10 BuchiAutomaton, CounterExample, CounterExampleGuidedRefinement, CtlFormula, CtlModelChecker,
11 CtlStarFormula, KripkeStructure, LtlFormula, LtlModelChecker, MuCalculusEvaluator, MuFormula,
12 ParityGameZielonka, ProbabilisticMCVerifier, SpuriousCounterexample, StateLabel,
13 SymbolicTransitionRelation, BDD,
14};
15
16pub fn app(f: Expr, a: Expr) -> Expr {
17 Expr::App(Box::new(f), Box::new(a))
18}
19pub fn app2(f: Expr, a: Expr, b: Expr) -> Expr {
20 app(app(f, a), b)
21}
22pub fn app3(f: Expr, a: Expr, b: Expr, c: Expr) -> Expr {
23 app(app2(f, a, b), c)
24}
25pub fn cst(s: &str) -> Expr {
26 Expr::Const(Name::str(s), vec![])
27}
28pub fn prop() -> Expr {
29 Expr::Sort(Level::zero())
30}
31pub fn type0() -> Expr {
32 Expr::Sort(Level::succ(Level::zero()))
33}
34pub fn pi(bi: BinderInfo, name: &str, dom: Expr, body: Expr) -> Expr {
35 Expr::Pi(bi, Name::str(name), Box::new(dom), Box::new(body))
36}
37pub fn arrow(a: Expr, b: Expr) -> Expr {
38 pi(BinderInfo::Default, "_", a, b)
39}
40pub fn impl_pi(name: &str, dom: Expr, body: Expr) -> Expr {
41 pi(BinderInfo::Implicit, name, dom, body)
42}
43pub fn bvar(n: u32) -> Expr {
44 Expr::BVar(n)
45}
46pub fn nat_ty() -> Expr {
47 cst("Nat")
48}
49pub fn bool_ty() -> Expr {
50 cst("Bool")
51}
52pub fn kripke_structure_ty() -> Expr {
54 type0()
55}
56pub fn atomic_proposition_ty() -> Expr {
58 type0()
59}
60pub fn state_label_ty() -> Expr {
62 arrow(cst("State"), type0())
63}
64pub fn reachable_states_ty() -> Expr {
66 arrow(cst("KripkeStructure"), app(cst("List"), cst("State")))
67}
68pub fn is_connected_ty() -> Expr {
70 arrow(cst("KripkeStructure"), prop())
71}
72pub fn compute_scc_ty() -> Expr {
74 arrow(
75 cst("KripkeStructure"),
76 app(cst("List"), app(cst("List"), cst("State"))),
77 )
78}
79pub fn ltl_formula_ty() -> Expr {
81 type0()
82}
83pub fn ctl_formula_ty() -> Expr {
85 type0()
86}
87pub fn ctl_star_formula_ty() -> Expr {
89 type0()
90}
91pub fn ltl_is_safety_ty() -> Expr {
93 arrow(cst("LtlFormula"), prop())
94}
95pub fn ltl_is_liveness_ty() -> Expr {
97 arrow(cst("LtlFormula"), prop())
98}
99pub fn ltl_is_fairness_ty() -> Expr {
101 arrow(cst("LtlFormula"), prop())
102}
103pub fn ltl_model_checker_ty() -> Expr {
105 type0()
106}
107pub fn ctl_model_checker_ty() -> Expr {
109 type0()
110}
111pub fn counter_example_ty() -> Expr {
113 type0()
114}
115pub fn buchi_automaton_ty() -> Expr {
117 type0()
118}
119pub fn check_ltl_ty() -> Expr {
121 arrow(cst("KripkeStructure"), arrow(cst("LtlFormula"), bool_ty()))
122}
123pub fn check_ctl_ty() -> Expr {
125 arrow(cst("KripkeStructure"), arrow(cst("CtlFormula"), bool_ty()))
126}
127pub fn find_counterexample_ty() -> Expr {
129 arrow(
130 cst("KripkeStructure"),
131 arrow(cst("LtlFormula"), app(cst("Option"), cst("CounterExample"))),
132 )
133}
134pub fn bdd_ty() -> Expr {
136 type0()
137}
138pub fn bdd_manager_ty() -> Expr {
140 type0()
141}
142pub fn symbolic_transition_relation_ty() -> Expr {
144 type0()
145}
146pub fn image_ty() -> Expr {
148 arrow(
149 cst("BDDManager"),
150 arrow(
151 cst("BDD"),
152 arrow(cst("SymbolicTransitionRelation"), cst("BDD")),
153 ),
154 )
155}
156pub fn pre_image_ty() -> Expr {
158 arrow(
159 cst("BDDManager"),
160 arrow(
161 cst("BDD"),
162 arrow(cst("SymbolicTransitionRelation"), cst("BDD")),
163 ),
164 )
165}
166pub fn abstract_domain_ty() -> Expr {
168 type0()
169}
170pub fn abstract_transformer_ty() -> Expr {
172 arrow(
173 cst("AbstractDomain"),
174 arrow(cst("AbstractDomain"), cst("AbstractDomain")),
175 )
176}
177pub fn cegar_ty() -> Expr {
179 type0()
180}
181pub fn spurious_counterexample_ty() -> Expr {
183 type0()
184}
185pub fn abstract_states_ty() -> Expr {
187 arrow(app(cst("List"), cst("State")), cst("AbstractDomain"))
188}
189pub fn refine_abstraction_ty() -> Expr {
191 arrow(
192 cst("AbstractDomain"),
193 arrow(cst("SpuriousCounterexample"), cst("AbstractDomain")),
194 )
195}
196pub fn check_feasibility_ty() -> Expr {
198 arrow(cst("CounterExample"), bool_ty())
199}
200pub fn mu_formula_ty() -> Expr {
202 type0()
203}
204pub fn mu_fixpoint_ty() -> Expr {
207 arrow(arrow(cst("State"), prop()), arrow(cst("State"), prop()))
208}
209pub fn nu_fixpoint_ty() -> Expr {
212 arrow(arrow(cst("State"), prop()), arrow(cst("State"), prop()))
213}
214pub fn check_mu_ty() -> Expr {
217 arrow(cst("KripkeStructure"), arrow(cst("MuFormula"), bool_ty()))
218}
219pub fn alternating_turing_machine_ty() -> Expr {
221 type0()
222}
223pub fn alc_concept_ty() -> Expr {
225 type0()
226}
227pub fn parity_game_ty() -> Expr {
229 type0()
230}
231pub fn parity_condition_ty() -> Expr {
234 arrow(arrow(nat_ty(), bool_ty()), prop())
235}
236pub fn zielonka_solver_ty() -> Expr {
239 arrow(cst("ParityGame"), bool_ty())
240}
241pub fn parity_game_winner_ty() -> Expr {
244 arrow(cst("ParityGame"), arrow(nat_ty(), bool_ty()))
245}
246pub fn mu_calculus_parity_reduction_ty() -> Expr {
249 arrow(cst("MuFormula"), cst("ParityGame"))
250}
251pub fn sat_solver_ty() -> Expr {
253 type0()
254}
255pub fn bounded_mc_query_ty() -> Expr {
258 arrow(
259 cst("KripkeStructure"),
260 arrow(cst("LtlFormula"), arrow(nat_ty(), bool_ty())),
261 )
262}
263pub fn k_induction_result_ty() -> Expr {
265 type0()
266}
267pub fn k_induction_check_ty() -> Expr {
270 arrow(
271 cst("KripkeStructure"),
272 arrow(cst("LtlFormula"), arrow(nat_ty(), cst("KInductionResult"))),
273 )
274}
275pub fn probabilistic_kripke_ty() -> Expr {
277 type0()
278}
279pub fn pctl_formula_ty() -> Expr {
281 type0()
282}
283pub fn check_pctl_ty() -> Expr {
286 arrow(
287 cst("ProbabilisticKripke"),
288 arrow(cst("PCTLFormula"), bool_ty()),
289 )
290}
291pub fn reachability_probability_ty() -> Expr {
294 arrow(
295 cst("ProbabilisticKripke"),
296 arrow(
297 cst("State"),
298 arrow(app(cst("Set"), cst("State")), cst("Real")),
299 ),
300 )
301}
302pub fn timed_automaton_ty() -> Expr {
304 type0()
305}
306pub fn tctl_formula_ty() -> Expr {
308 type0()
309}
310pub fn zone_graph_ty() -> Expr {
312 type0()
313}
314pub fn check_tctl_ty() -> Expr {
317 arrow(cst("TimedAutomaton"), arrow(cst("TCTLFormula"), bool_ty()))
318}
319pub fn zone_reachability_ty() -> Expr {
322 arrow(cst("TimedAutomaton"), cst("ZoneGraph"))
323}
324pub fn hybrid_automaton_ty() -> Expr {
326 type0()
327}
328pub fn flow_condition_ty() -> Expr {
331 arrow(type0(), prop())
332}
333pub fn guard_region_ty() -> Expr {
336 arrow(type0(), prop())
337}
338pub fn hybrid_reachability_ty() -> Expr {
341 arrow(cst("HybridAutomaton"), app(cst("Set"), type0()))
342}
343pub fn pushdown_system_ty() -> Expr {
345 type0()
346}
347pub fn context_free_ltl_ty() -> Expr {
349 type0()
350}
351pub fn check_pushdown_ltl_ty() -> Expr {
354 arrow(cst("PushdownSystem"), arrow(cst("LtlFormula"), bool_ty()))
355}
356pub fn pushdown_reachability_ty() -> Expr {
359 arrow(cst("PushdownSystem"), app(cst("Set"), cst("State")))
360}
361pub fn hors_ty() -> Expr {
363 type0()
364}
365pub fn hors_model_checking_ty() -> Expr {
368 arrow(
369 cst("HigherOrderRecursionScheme"),
370 arrow(cst("MuFormula"), bool_ty()),
371 )
372}
373pub fn craig_interpolant_ty() -> Expr {
376 arrow(
377 cst("LtlFormula"),
378 arrow(cst("LtlFormula"), arrow(cst("LtlFormula"), prop())),
379 )
380}
381pub fn lazy_cegar_ty() -> Expr {
384 arrow(cst("KripkeStructure"), arrow(cst("LtlFormula"), bool_ty()))
385}
386pub fn assume_guarantee_contract_ty() -> Expr {
388 type0()
389}
390pub fn ag_decomposition_ty() -> Expr {
393 arrow(
394 cst("KripkeStructure"),
395 arrow(cst("AssumeGuaranteeContract"), bool_ty()),
396 )
397}
398pub fn interface_verification_ty() -> Expr {
401 arrow(app(cst("List"), cst("AssumeGuaranteeContract")), bool_ty())
402}
403pub fn mazurkiewicz_trace_ty() -> Expr {
405 type0()
406}
407pub fn persistent_set_ty() -> Expr {
410 arrow(
411 cst("KripkeStructure"),
412 arrow(
413 cst("State"),
414 arrow(app(cst("Set"), arrow(cst("State"), cst("State"))), prop()),
415 ),
416 )
417}
418pub fn ample_set_ty() -> Expr {
421 arrow(
422 cst("KripkeStructure"),
423 arrow(
424 cst("State"),
425 arrow(app(cst("Set"), arrow(cst("State"), cst("State"))), prop()),
426 ),
427 )
428}
429pub fn por_reduction_ty() -> Expr {
432 arrow(cst("KripkeStructure"), cst("KripkeStructure"))
433}
434pub fn psl_formula_ty() -> Expr {
436 type0()
437}
438pub fn sva_formula_ty() -> Expr {
440 type0()
441}
442pub fn check_psl_ty() -> Expr {
445 arrow(cst("KripkeStructure"), arrow(cst("PSLFormula"), bool_ty()))
446}
447pub fn temporal_logic_pattern_ty() -> Expr {
449 type0()
450}
451pub fn build_env(env: &mut Environment) {
453 let axioms: &[(&str, Expr)] = &[
454 ("KripkeStructure", kripke_structure_ty()),
455 ("AtomicProposition", atomic_proposition_ty()),
456 ("StateLabel", state_label_ty()),
457 ("State", type0()),
458 ("reachable_states", reachable_states_ty()),
459 ("is_connected", is_connected_ty()),
460 ("compute_scc", compute_scc_ty()),
461 ("LtlFormula", ltl_formula_ty()),
462 ("CtlFormula", ctl_formula_ty()),
463 ("CtlStarFormula", ctl_star_formula_ty()),
464 ("ltl_is_safety", ltl_is_safety_ty()),
465 ("ltl_is_liveness", ltl_is_liveness_ty()),
466 ("ltl_is_fairness", ltl_is_fairness_ty()),
467 ("LtlModelChecker", ltl_model_checker_ty()),
468 ("CtlModelChecker", ctl_model_checker_ty()),
469 ("CounterExample", counter_example_ty()),
470 ("BuchiAutomaton", buchi_automaton_ty()),
471 ("Option", arrow(type0(), type0())),
472 ("check_ltl", check_ltl_ty()),
473 ("check_ctl", check_ctl_ty()),
474 ("find_counterexample", find_counterexample_ty()),
475 ("BDD", bdd_ty()),
476 ("BDDManager", bdd_manager_ty()),
477 (
478 "SymbolicTransitionRelation",
479 symbolic_transition_relation_ty(),
480 ),
481 ("image", image_ty()),
482 ("pre_image", pre_image_ty()),
483 ("AbstractDomain", abstract_domain_ty()),
484 ("AbstractTransformer", abstract_transformer_ty()),
485 ("CounterExampleGuidedRefinement", cegar_ty()),
486 ("SpuriousCounterexample", spurious_counterexample_ty()),
487 ("abstract_states", abstract_states_ty()),
488 ("refine_abstraction", refine_abstraction_ty()),
489 ("check_feasibility", check_feasibility_ty()),
490 ("MuFormula", mu_formula_ty()),
491 ("mu_fixpoint", mu_fixpoint_ty()),
492 ("nu_fixpoint", nu_fixpoint_ty()),
493 ("check_mu", check_mu_ty()),
494 ("AlternatingTuringMachine", alternating_turing_machine_ty()),
495 ("ALCConcept", alc_concept_ty()),
496 ("ParityGame", parity_game_ty()),
497 ("ParityCondition", parity_condition_ty()),
498 ("ZielonkaSolver", zielonka_solver_ty()),
499 ("parity_game_winner", parity_game_winner_ty()),
500 (
501 "mu_calculus_parity_reduction",
502 mu_calculus_parity_reduction_ty(),
503 ),
504 ("SatSolver", sat_solver_ty()),
505 ("BoundedMCQuery", bounded_mc_query_ty()),
506 ("KInductionResult", k_induction_result_ty()),
507 ("k_induction_check", k_induction_check_ty()),
508 ("ProbabilisticKripke", probabilistic_kripke_ty()),
509 ("PCTLFormula", pctl_formula_ty()),
510 ("check_pctl", check_pctl_ty()),
511 ("reachability_probability", reachability_probability_ty()),
512 ("TimedAutomaton", timed_automaton_ty()),
513 ("TCTLFormula", tctl_formula_ty()),
514 ("ZoneGraph", zone_graph_ty()),
515 ("check_tctl", check_tctl_ty()),
516 ("zone_reachability", zone_reachability_ty()),
517 ("HybridAutomaton", hybrid_automaton_ty()),
518 ("FlowCondition", flow_condition_ty()),
519 ("GuardRegion", guard_region_ty()),
520 ("HybridReachability", hybrid_reachability_ty()),
521 ("PushdownSystem", pushdown_system_ty()),
522 ("ContextFreeLTL", context_free_ltl_ty()),
523 ("check_pushdown_ltl", check_pushdown_ltl_ty()),
524 ("pushdown_reachability", pushdown_reachability_ty()),
525 ("HigherOrderRecursionScheme", hors_ty()),
526 ("HORSModelChecking", hors_model_checking_ty()),
527 ("CraigInterpolant", craig_interpolant_ty()),
528 ("lazy_cegar", lazy_cegar_ty()),
529 ("AssumeGuaranteeContract", assume_guarantee_contract_ty()),
530 ("ag_decomposition", ag_decomposition_ty()),
531 ("interface_verification", interface_verification_ty()),
532 ("MazurkiewiczTrace", mazurkiewicz_trace_ty()),
533 ("PersistentSet", persistent_set_ty()),
534 ("AmpleSet", ample_set_ty()),
535 ("por_reduction", por_reduction_ty()),
536 ("PSLFormula", psl_formula_ty()),
537 ("SVAFormula", sva_formula_ty()),
538 ("check_psl", check_psl_ty()),
539 ("TemporalLogicPattern", temporal_logic_pattern_ty()),
540 ("Real", cst("Real")),
541 ];
542 for (name, ty) in axioms {
543 env.add(Declaration::Axiom {
544 name: Name::str(*name),
545 univ_params: vec![],
546 ty: ty.clone(),
547 })
548 .ok();
549 }
550}
551#[cfg(test)]
552mod new_impl_tests {
553 use super::*;
554 fn small_kripke() -> KripkeStructure {
555 let mut k = KripkeStructure::new(3);
556 k.add_initial(0);
557 k.add_transition(0, 1);
558 k.add_transition(1, 2);
559 k.add_transition(2, 0);
560 k.label_state(0, "p");
561 k.label_state(1, "q");
562 k
563 }
564 #[test]
565 fn test_mu_calculus_evaluator_true() {
566 let k = small_kripke();
567 let mc = MuCalculusEvaluator::new(k);
568 let f = MuFormula::True_;
569 assert!(mc.check(&f));
570 }
571 #[test]
572 fn test_mu_calculus_evaluator_prop() {
573 let k = small_kripke();
574 let mc = MuCalculusEvaluator::new(k);
575 let f = MuFormula::Prop("p".to_string());
576 assert!(mc.check(&f));
577 }
578 #[test]
579 fn test_mu_calculus_evaluator_diamond() {
580 let k = small_kripke();
581 let mc = MuCalculusEvaluator::new(k);
582 let f = MuFormula::Diamond(Box::new(MuFormula::Prop("q".to_string())));
583 assert!(mc.check(&f));
584 }
585 #[test]
586 fn test_mu_calculus_evaluator_nu_box() {
587 let k = small_kripke();
588 let mc = MuCalculusEvaluator::new(k.clone());
589 let f = MuFormula::Nu("X".to_string(), Box::new(MuFormula::True_));
590 let mut env = HashMap::new();
591 let sat = mc.eval(&f, &mut env);
592 assert_eq!(sat.len(), k.num_states);
593 }
594 #[test]
595 fn test_parity_game_zielonka_trivial() {
596 let mut pg = ParityGameZielonka::new(1);
597 pg.set_priority(0, 0);
598 pg.set_owner(0, 1);
599 pg.add_edge(0, 0);
600 let (w0, _w1) = pg.solve();
601 assert!(w0.contains(&0));
602 }
603 #[test]
604 fn test_parity_game_zielonka_two_nodes() {
605 let mut pg = ParityGameZielonka::new(2);
606 pg.set_priority(0, 1);
607 pg.set_priority(1, 2);
608 pg.set_owner(0, 0);
609 pg.set_owner(1, 1);
610 pg.add_edge(0, 1);
611 pg.add_edge(1, 0);
612 let (w0, _w1) = pg.solve();
613 assert!(!w0.is_empty() || pg.player0_wins(0));
614 }
615 #[test]
616 fn test_bdd_model_checker_new() {
617 let mut bmc = BDDModelChecker::new(2);
618 let t = bmc.mgr.true_node();
619 let f = bmc.mgr.false_node();
620 bmc.set_init(t);
621 bmc.set_trans(f);
622 let reach = bmc.reachable();
623 assert_eq!(reach, t);
624 assert!(bmc.check_ag_safe(t));
625 assert!(!bmc.check_ef(f));
626 }
627 #[test]
628 fn test_bdd_model_checker_variable() {
629 let mut bmc = BDDModelChecker::new(2);
630 let v0 = bmc.mgr.var(0);
631 let v1 = bmc.mgr.var(1);
632 let combined = bmc.mgr.bdd_and(v0, v1);
633 assert!(combined < bmc.mgr.nodes.len());
634 }
635 #[test]
636 fn test_probabilistic_mc_verifier() {
637 let mut mc = ProbabilisticMCVerifier::new(3);
638 mc.set_initial(0, 1.0);
639 mc.add_transition(0, 1, 0.6);
640 mc.add_transition(0, 2, 0.4);
641 mc.add_transition(1, 1, 1.0);
642 mc.add_transition(2, 2, 1.0);
643 mc.label_state(1, "good");
644 mc.label_state(2, "bad");
645 let target: HashSet<usize> = [1].iter().copied().collect();
646 let prob = mc.reachability_prob(&target);
647 assert!((prob[0] - 0.6).abs() < 1e-6);
648 assert!(mc.check_prob_reach("good", 0.5));
649 assert!(!mc.check_prob_reach("good", 0.7));
650 }
651 #[test]
652 fn test_mc_env_new_axioms() {
653 let mut env = Environment::new();
654 build_env(&mut env);
655 assert!(env.get(&Name::str("MuFormula")).is_some());
656 assert!(env.get(&Name::str("mu_fixpoint")).is_some());
657 assert!(env.get(&Name::str("check_mu")).is_some());
658 assert!(env.get(&Name::str("ParityGame")).is_some());
659 assert!(env.get(&Name::str("ZielonkaSolver")).is_some());
660 assert!(env
661 .get(&Name::str("mu_calculus_parity_reduction"))
662 .is_some());
663 assert!(env.get(&Name::str("BoundedMCQuery")).is_some());
664 assert!(env.get(&Name::str("k_induction_check")).is_some());
665 assert!(env.get(&Name::str("PCTLFormula")).is_some());
666 assert!(env.get(&Name::str("reachability_probability")).is_some());
667 assert!(env.get(&Name::str("TimedAutomaton")).is_some());
668 assert!(env.get(&Name::str("zone_reachability")).is_some());
669 assert!(env.get(&Name::str("HybridAutomaton")).is_some());
670 assert!(env.get(&Name::str("HybridReachability")).is_some());
671 assert!(env.get(&Name::str("PushdownSystem")).is_some());
672 assert!(env.get(&Name::str("check_pushdown_ltl")).is_some());
673 assert!(env.get(&Name::str("HigherOrderRecursionScheme")).is_some());
674 assert!(env.get(&Name::str("CraigInterpolant")).is_some());
675 assert!(env.get(&Name::str("lazy_cegar")).is_some());
676 assert!(env.get(&Name::str("AssumeGuaranteeContract")).is_some());
677 assert!(env.get(&Name::str("interface_verification")).is_some());
678 assert!(env.get(&Name::str("MazurkiewiczTrace")).is_some());
679 assert!(env.get(&Name::str("AmpleSet")).is_some());
680 assert!(env.get(&Name::str("por_reduction")).is_some());
681 assert!(env.get(&Name::str("PSLFormula")).is_some());
682 assert!(env.get(&Name::str("SVAFormula")).is_some());
683 assert!(env.get(&Name::str("check_psl")).is_some());
684 }
685}