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