use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
use std::collections::{HashMap, HashSet, VecDeque};
use super::types::{
AbstractDomain, AbstractTransformer, AtomicProposition, BDDManager, BDDModelChecker,
BuchiAutomaton, CounterExample, CounterExampleGuidedRefinement, CtlFormula, CtlModelChecker,
CtlStarFormula, KripkeStructure, LtlFormula, LtlModelChecker, MuCalculusEvaluator, MuFormula,
ParityGameZielonka, ProbabilisticMCVerifier, SpuriousCounterexample, StateLabel,
SymbolicTransitionRelation, BDD,
};
pub fn app(f: Expr, a: Expr) -> Expr {
Expr::App(Box::new(f), Box::new(a))
}
pub fn app2(f: Expr, a: Expr, b: Expr) -> Expr {
app(app(f, a), b)
}
pub fn app3(f: Expr, a: Expr, b: Expr, c: Expr) -> Expr {
app(app2(f, a, b), c)
}
pub fn cst(s: &str) -> Expr {
Expr::Const(Name::str(s), vec![])
}
pub fn prop() -> Expr {
Expr::Sort(Level::zero())
}
pub fn type0() -> Expr {
Expr::Sort(Level::succ(Level::zero()))
}
pub fn pi(bi: BinderInfo, name: &str, dom: Expr, body: Expr) -> Expr {
Expr::Pi(bi, Name::str(name), Box::new(dom), Box::new(body))
}
pub fn arrow(a: Expr, b: Expr) -> Expr {
pi(BinderInfo::Default, "_", a, b)
}
pub fn impl_pi(name: &str, dom: Expr, body: Expr) -> Expr {
pi(BinderInfo::Implicit, name, dom, body)
}
pub fn bvar(n: u32) -> Expr {
Expr::BVar(n)
}
pub fn nat_ty() -> Expr {
cst("Nat")
}
pub fn bool_ty() -> Expr {
cst("Bool")
}
pub fn kripke_structure_ty() -> Expr {
type0()
}
pub fn atomic_proposition_ty() -> Expr {
type0()
}
pub fn state_label_ty() -> Expr {
arrow(cst("State"), type0())
}
pub fn reachable_states_ty() -> Expr {
arrow(cst("KripkeStructure"), app(cst("List"), cst("State")))
}
pub fn is_connected_ty() -> Expr {
arrow(cst("KripkeStructure"), prop())
}
pub fn compute_scc_ty() -> Expr {
arrow(
cst("KripkeStructure"),
app(cst("List"), app(cst("List"), cst("State"))),
)
}
pub fn ltl_formula_ty() -> Expr {
type0()
}
pub fn ctl_formula_ty() -> Expr {
type0()
}
pub fn ctl_star_formula_ty() -> Expr {
type0()
}
pub fn ltl_is_safety_ty() -> Expr {
arrow(cst("LtlFormula"), prop())
}
pub fn ltl_is_liveness_ty() -> Expr {
arrow(cst("LtlFormula"), prop())
}
pub fn ltl_is_fairness_ty() -> Expr {
arrow(cst("LtlFormula"), prop())
}
pub fn ltl_model_checker_ty() -> Expr {
type0()
}
pub fn ctl_model_checker_ty() -> Expr {
type0()
}
pub fn counter_example_ty() -> Expr {
type0()
}
pub fn buchi_automaton_ty() -> Expr {
type0()
}
pub fn check_ltl_ty() -> Expr {
arrow(cst("KripkeStructure"), arrow(cst("LtlFormula"), bool_ty()))
}
pub fn check_ctl_ty() -> Expr {
arrow(cst("KripkeStructure"), arrow(cst("CtlFormula"), bool_ty()))
}
pub fn find_counterexample_ty() -> Expr {
arrow(
cst("KripkeStructure"),
arrow(cst("LtlFormula"), app(cst("Option"), cst("CounterExample"))),
)
}
pub fn bdd_ty() -> Expr {
type0()
}
pub fn bdd_manager_ty() -> Expr {
type0()
}
pub fn symbolic_transition_relation_ty() -> Expr {
type0()
}
pub fn image_ty() -> Expr {
arrow(
cst("BDDManager"),
arrow(
cst("BDD"),
arrow(cst("SymbolicTransitionRelation"), cst("BDD")),
),
)
}
pub fn pre_image_ty() -> Expr {
arrow(
cst("BDDManager"),
arrow(
cst("BDD"),
arrow(cst("SymbolicTransitionRelation"), cst("BDD")),
),
)
}
pub fn abstract_domain_ty() -> Expr {
type0()
}
pub fn abstract_transformer_ty() -> Expr {
arrow(
cst("AbstractDomain"),
arrow(cst("AbstractDomain"), cst("AbstractDomain")),
)
}
pub fn cegar_ty() -> Expr {
type0()
}
pub fn spurious_counterexample_ty() -> Expr {
type0()
}
pub fn abstract_states_ty() -> Expr {
arrow(app(cst("List"), cst("State")), cst("AbstractDomain"))
}
pub fn refine_abstraction_ty() -> Expr {
arrow(
cst("AbstractDomain"),
arrow(cst("SpuriousCounterexample"), cst("AbstractDomain")),
)
}
pub fn check_feasibility_ty() -> Expr {
arrow(cst("CounterExample"), bool_ty())
}
pub fn mu_formula_ty() -> Expr {
type0()
}
pub fn mu_fixpoint_ty() -> Expr {
arrow(arrow(cst("State"), prop()), arrow(cst("State"), prop()))
}
pub fn nu_fixpoint_ty() -> Expr {
arrow(arrow(cst("State"), prop()), arrow(cst("State"), prop()))
}
pub fn check_mu_ty() -> Expr {
arrow(cst("KripkeStructure"), arrow(cst("MuFormula"), bool_ty()))
}
pub fn alternating_turing_machine_ty() -> Expr {
type0()
}
pub fn alc_concept_ty() -> Expr {
type0()
}
pub fn parity_game_ty() -> Expr {
type0()
}
pub fn parity_condition_ty() -> Expr {
arrow(arrow(nat_ty(), bool_ty()), prop())
}
pub fn zielonka_solver_ty() -> Expr {
arrow(cst("ParityGame"), bool_ty())
}
pub fn parity_game_winner_ty() -> Expr {
arrow(cst("ParityGame"), arrow(nat_ty(), bool_ty()))
}
pub fn mu_calculus_parity_reduction_ty() -> Expr {
arrow(cst("MuFormula"), cst("ParityGame"))
}
pub fn sat_solver_ty() -> Expr {
type0()
}
pub fn bounded_mc_query_ty() -> Expr {
arrow(
cst("KripkeStructure"),
arrow(cst("LtlFormula"), arrow(nat_ty(), bool_ty())),
)
}
pub fn k_induction_result_ty() -> Expr {
type0()
}
pub fn k_induction_check_ty() -> Expr {
arrow(
cst("KripkeStructure"),
arrow(cst("LtlFormula"), arrow(nat_ty(), cst("KInductionResult"))),
)
}
pub fn probabilistic_kripke_ty() -> Expr {
type0()
}
pub fn pctl_formula_ty() -> Expr {
type0()
}
pub fn check_pctl_ty() -> Expr {
arrow(
cst("ProbabilisticKripke"),
arrow(cst("PCTLFormula"), bool_ty()),
)
}
pub fn reachability_probability_ty() -> Expr {
arrow(
cst("ProbabilisticKripke"),
arrow(
cst("State"),
arrow(app(cst("Set"), cst("State")), cst("Real")),
),
)
}
pub fn timed_automaton_ty() -> Expr {
type0()
}
pub fn tctl_formula_ty() -> Expr {
type0()
}
pub fn zone_graph_ty() -> Expr {
type0()
}
pub fn check_tctl_ty() -> Expr {
arrow(cst("TimedAutomaton"), arrow(cst("TCTLFormula"), bool_ty()))
}
pub fn zone_reachability_ty() -> Expr {
arrow(cst("TimedAutomaton"), cst("ZoneGraph"))
}
pub fn hybrid_automaton_ty() -> Expr {
type0()
}
pub fn flow_condition_ty() -> Expr {
arrow(type0(), prop())
}
pub fn guard_region_ty() -> Expr {
arrow(type0(), prop())
}
pub fn hybrid_reachability_ty() -> Expr {
arrow(cst("HybridAutomaton"), app(cst("Set"), type0()))
}
pub fn pushdown_system_ty() -> Expr {
type0()
}
pub fn context_free_ltl_ty() -> Expr {
type0()
}
pub fn check_pushdown_ltl_ty() -> Expr {
arrow(cst("PushdownSystem"), arrow(cst("LtlFormula"), bool_ty()))
}
pub fn pushdown_reachability_ty() -> Expr {
arrow(cst("PushdownSystem"), app(cst("Set"), cst("State")))
}
pub fn hors_ty() -> Expr {
type0()
}
pub fn hors_model_checking_ty() -> Expr {
arrow(
cst("HigherOrderRecursionScheme"),
arrow(cst("MuFormula"), bool_ty()),
)
}
pub fn craig_interpolant_ty() -> Expr {
arrow(
cst("LtlFormula"),
arrow(cst("LtlFormula"), arrow(cst("LtlFormula"), prop())),
)
}
pub fn lazy_cegar_ty() -> Expr {
arrow(cst("KripkeStructure"), arrow(cst("LtlFormula"), bool_ty()))
}
pub fn assume_guarantee_contract_ty() -> Expr {
type0()
}
pub fn ag_decomposition_ty() -> Expr {
arrow(
cst("KripkeStructure"),
arrow(cst("AssumeGuaranteeContract"), bool_ty()),
)
}
pub fn interface_verification_ty() -> Expr {
arrow(app(cst("List"), cst("AssumeGuaranteeContract")), bool_ty())
}
pub fn mazurkiewicz_trace_ty() -> Expr {
type0()
}
pub fn persistent_set_ty() -> Expr {
arrow(
cst("KripkeStructure"),
arrow(
cst("State"),
arrow(app(cst("Set"), arrow(cst("State"), cst("State"))), prop()),
),
)
}
pub fn ample_set_ty() -> Expr {
arrow(
cst("KripkeStructure"),
arrow(
cst("State"),
arrow(app(cst("Set"), arrow(cst("State"), cst("State"))), prop()),
),
)
}
pub fn por_reduction_ty() -> Expr {
arrow(cst("KripkeStructure"), cst("KripkeStructure"))
}
pub fn psl_formula_ty() -> Expr {
type0()
}
pub fn sva_formula_ty() -> Expr {
type0()
}
pub fn check_psl_ty() -> Expr {
arrow(cst("KripkeStructure"), arrow(cst("PSLFormula"), bool_ty()))
}
pub fn temporal_logic_pattern_ty() -> Expr {
type0()
}
pub fn build_env(env: &mut Environment) {
let axioms: &[(&str, Expr)] = &[
("KripkeStructure", kripke_structure_ty()),
("AtomicProposition", atomic_proposition_ty()),
("StateLabel", state_label_ty()),
("State", type0()),
("reachable_states", reachable_states_ty()),
("is_connected", is_connected_ty()),
("compute_scc", compute_scc_ty()),
("LtlFormula", ltl_formula_ty()),
("CtlFormula", ctl_formula_ty()),
("CtlStarFormula", ctl_star_formula_ty()),
("ltl_is_safety", ltl_is_safety_ty()),
("ltl_is_liveness", ltl_is_liveness_ty()),
("ltl_is_fairness", ltl_is_fairness_ty()),
("LtlModelChecker", ltl_model_checker_ty()),
("CtlModelChecker", ctl_model_checker_ty()),
("CounterExample", counter_example_ty()),
("BuchiAutomaton", buchi_automaton_ty()),
("Option", arrow(type0(), type0())),
("check_ltl", check_ltl_ty()),
("check_ctl", check_ctl_ty()),
("find_counterexample", find_counterexample_ty()),
("BDD", bdd_ty()),
("BDDManager", bdd_manager_ty()),
(
"SymbolicTransitionRelation",
symbolic_transition_relation_ty(),
),
("image", image_ty()),
("pre_image", pre_image_ty()),
("AbstractDomain", abstract_domain_ty()),
("AbstractTransformer", abstract_transformer_ty()),
("CounterExampleGuidedRefinement", cegar_ty()),
("SpuriousCounterexample", spurious_counterexample_ty()),
("abstract_states", abstract_states_ty()),
("refine_abstraction", refine_abstraction_ty()),
("check_feasibility", check_feasibility_ty()),
("MuFormula", mu_formula_ty()),
("mu_fixpoint", mu_fixpoint_ty()),
("nu_fixpoint", nu_fixpoint_ty()),
("check_mu", check_mu_ty()),
("AlternatingTuringMachine", alternating_turing_machine_ty()),
("ALCConcept", alc_concept_ty()),
("ParityGame", parity_game_ty()),
("ParityCondition", parity_condition_ty()),
("ZielonkaSolver", zielonka_solver_ty()),
("parity_game_winner", parity_game_winner_ty()),
(
"mu_calculus_parity_reduction",
mu_calculus_parity_reduction_ty(),
),
("SatSolver", sat_solver_ty()),
("BoundedMCQuery", bounded_mc_query_ty()),
("KInductionResult", k_induction_result_ty()),
("k_induction_check", k_induction_check_ty()),
("ProbabilisticKripke", probabilistic_kripke_ty()),
("PCTLFormula", pctl_formula_ty()),
("check_pctl", check_pctl_ty()),
("reachability_probability", reachability_probability_ty()),
("TimedAutomaton", timed_automaton_ty()),
("TCTLFormula", tctl_formula_ty()),
("ZoneGraph", zone_graph_ty()),
("check_tctl", check_tctl_ty()),
("zone_reachability", zone_reachability_ty()),
("HybridAutomaton", hybrid_automaton_ty()),
("FlowCondition", flow_condition_ty()),
("GuardRegion", guard_region_ty()),
("HybridReachability", hybrid_reachability_ty()),
("PushdownSystem", pushdown_system_ty()),
("ContextFreeLTL", context_free_ltl_ty()),
("check_pushdown_ltl", check_pushdown_ltl_ty()),
("pushdown_reachability", pushdown_reachability_ty()),
("HigherOrderRecursionScheme", hors_ty()),
("HORSModelChecking", hors_model_checking_ty()),
("CraigInterpolant", craig_interpolant_ty()),
("lazy_cegar", lazy_cegar_ty()),
("AssumeGuaranteeContract", assume_guarantee_contract_ty()),
("ag_decomposition", ag_decomposition_ty()),
("interface_verification", interface_verification_ty()),
("MazurkiewiczTrace", mazurkiewicz_trace_ty()),
("PersistentSet", persistent_set_ty()),
("AmpleSet", ample_set_ty()),
("por_reduction", por_reduction_ty()),
("PSLFormula", psl_formula_ty()),
("SVAFormula", sva_formula_ty()),
("check_psl", check_psl_ty()),
("TemporalLogicPattern", temporal_logic_pattern_ty()),
("Real", cst("Real")),
];
for (name, ty) in axioms {
env.add(Declaration::Axiom {
name: Name::str(*name),
univ_params: vec![],
ty: ty.clone(),
})
.ok();
}
}
#[cfg(test)]
mod new_impl_tests {
use super::*;
fn small_kripke() -> KripkeStructure {
let mut k = KripkeStructure::new(3);
k.add_initial(0);
k.add_transition(0, 1);
k.add_transition(1, 2);
k.add_transition(2, 0);
k.label_state(0, "p");
k.label_state(1, "q");
k
}
#[test]
fn test_mu_calculus_evaluator_true() {
let k = small_kripke();
let mc = MuCalculusEvaluator::new(k);
let f = MuFormula::True_;
assert!(mc.check(&f));
}
#[test]
fn test_mu_calculus_evaluator_prop() {
let k = small_kripke();
let mc = MuCalculusEvaluator::new(k);
let f = MuFormula::Prop("p".to_string());
assert!(mc.check(&f));
}
#[test]
fn test_mu_calculus_evaluator_diamond() {
let k = small_kripke();
let mc = MuCalculusEvaluator::new(k);
let f = MuFormula::Diamond(Box::new(MuFormula::Prop("q".to_string())));
assert!(mc.check(&f));
}
#[test]
fn test_mu_calculus_evaluator_nu_box() {
let k = small_kripke();
let mc = MuCalculusEvaluator::new(k.clone());
let f = MuFormula::Nu("X".to_string(), Box::new(MuFormula::True_));
let mut env = HashMap::new();
let sat = mc.eval(&f, &mut env);
assert_eq!(sat.len(), k.num_states);
}
#[test]
fn test_parity_game_zielonka_trivial() {
let mut pg = ParityGameZielonka::new(1);
pg.set_priority(0, 0);
pg.set_owner(0, 1);
pg.add_edge(0, 0);
let (w0, _w1) = pg.solve();
assert!(w0.contains(&0));
}
#[test]
fn test_parity_game_zielonka_two_nodes() {
let mut pg = ParityGameZielonka::new(2);
pg.set_priority(0, 1);
pg.set_priority(1, 2);
pg.set_owner(0, 0);
pg.set_owner(1, 1);
pg.add_edge(0, 1);
pg.add_edge(1, 0);
let (w0, _w1) = pg.solve();
assert!(!w0.is_empty() || pg.player0_wins(0));
}
#[test]
fn test_bdd_model_checker_new() {
let mut bmc = BDDModelChecker::new(2);
let t = bmc.mgr.true_node();
let f = bmc.mgr.false_node();
bmc.set_init(t);
bmc.set_trans(f);
let reach = bmc.reachable();
assert_eq!(reach, t);
assert!(bmc.check_ag_safe(t));
assert!(!bmc.check_ef(f));
}
#[test]
fn test_bdd_model_checker_variable() {
let mut bmc = BDDModelChecker::new(2);
let v0 = bmc.mgr.var(0);
let v1 = bmc.mgr.var(1);
let combined = bmc.mgr.bdd_and(v0, v1);
assert!(combined < bmc.mgr.nodes.len());
}
#[test]
fn test_probabilistic_mc_verifier() {
let mut mc = ProbabilisticMCVerifier::new(3);
mc.set_initial(0, 1.0);
mc.add_transition(0, 1, 0.6);
mc.add_transition(0, 2, 0.4);
mc.add_transition(1, 1, 1.0);
mc.add_transition(2, 2, 1.0);
mc.label_state(1, "good");
mc.label_state(2, "bad");
let target: HashSet<usize> = [1].iter().copied().collect();
let prob = mc.reachability_prob(&target);
assert!((prob[0] - 0.6).abs() < 1e-6);
assert!(mc.check_prob_reach("good", 0.5));
assert!(!mc.check_prob_reach("good", 0.7));
}
#[test]
fn test_mc_env_new_axioms() {
let mut env = Environment::new();
build_env(&mut env);
assert!(env.get(&Name::str("MuFormula")).is_some());
assert!(env.get(&Name::str("mu_fixpoint")).is_some());
assert!(env.get(&Name::str("check_mu")).is_some());
assert!(env.get(&Name::str("ParityGame")).is_some());
assert!(env.get(&Name::str("ZielonkaSolver")).is_some());
assert!(env
.get(&Name::str("mu_calculus_parity_reduction"))
.is_some());
assert!(env.get(&Name::str("BoundedMCQuery")).is_some());
assert!(env.get(&Name::str("k_induction_check")).is_some());
assert!(env.get(&Name::str("PCTLFormula")).is_some());
assert!(env.get(&Name::str("reachability_probability")).is_some());
assert!(env.get(&Name::str("TimedAutomaton")).is_some());
assert!(env.get(&Name::str("zone_reachability")).is_some());
assert!(env.get(&Name::str("HybridAutomaton")).is_some());
assert!(env.get(&Name::str("HybridReachability")).is_some());
assert!(env.get(&Name::str("PushdownSystem")).is_some());
assert!(env.get(&Name::str("check_pushdown_ltl")).is_some());
assert!(env.get(&Name::str("HigherOrderRecursionScheme")).is_some());
assert!(env.get(&Name::str("CraigInterpolant")).is_some());
assert!(env.get(&Name::str("lazy_cegar")).is_some());
assert!(env.get(&Name::str("AssumeGuaranteeContract")).is_some());
assert!(env.get(&Name::str("interface_verification")).is_some());
assert!(env.get(&Name::str("MazurkiewiczTrace")).is_some());
assert!(env.get(&Name::str("AmpleSet")).is_some());
assert!(env.get(&Name::str("por_reduction")).is_some());
assert!(env.get(&Name::str("PSLFormula")).is_some());
assert!(env.get(&Name::str("SVAFormula")).is_some());
assert!(env.get(&Name::str("check_psl")).is_some());
}
}