rust_formal_verification/models/finite_state_transition_system/
features.rs1use crate::algorithms::formula_logic::{does_a_imply_b, is_a_and_b_satisfiable};
6use crate::formulas::literal::VariableType;
7use crate::formulas::{Clause, Cube, Literal, CNF};
8use crate::solvers::sat::{Assignment, StatelessSatSolver};
9
10use super::FiniteStateTransitionSystem;
11
12impl FiniteStateTransitionSystem {
17 fn bump_all_clause_variables_by_some_number(
22 original_clause: &Clause,
23 number_to_bump: VariableType,
24 ) -> Clause {
25 let mut literals = Vec::new();
26 for literal in original_clause.iter() {
27 assert_ne!(literal.get_number(), 0);
28 let mut new_number = literal.get_number();
29 new_number += number_to_bump;
30 let is_negated = literal.is_negated();
31 let new_lit = Literal::new(new_number).negate_if_true(is_negated);
32 literals.push(new_lit);
33 }
34 Clause::new(&literals)
35 }
36
37 fn bump_all_cnf_variables_by_some_number(
38 original_cnf: &CNF,
39 number_to_bump: VariableType,
40 ) -> CNF {
41 if number_to_bump == 0 {
42 original_cnf.to_owned()
44 } else {
45 let mut cnf_to_add_to = CNF::new();
46 for clause in original_cnf.iter() {
47 let new_clause =
48 Self::bump_all_clause_variables_by_some_number(clause, number_to_bump);
49 cnf_to_add_to.add_clause(&new_clause);
50 }
51 cnf_to_add_to
52 }
53 }
54
55 pub fn add_tags_to_relation(&self, relation: &CNF, number_of_tags: VariableType) -> CNF {
60 Self::bump_all_cnf_variables_by_some_number(
61 relation,
62 self.max_literal_number * number_of_tags,
63 )
64 }
65
66 pub fn add_tags_to_cube(&self, cube: &Cube, number_of_tags: VariableType) -> Cube {
67 if number_of_tags == 0 {
68 cube.to_owned()
70 } else {
71 let bumped_as_clause = Self::bump_all_clause_variables_by_some_number(
72 &(!(cube.to_owned())),
73 self.max_literal_number * number_of_tags,
74 );
75 !bumped_as_clause
76 }
77 }
78
79 pub fn add_tags_to_clause(&self, clause: &Clause, number_of_tags: VariableType) -> Clause {
80 if number_of_tags == 0 {
81 clause.to_owned()
83 } else {
84 Self::bump_all_clause_variables_by_some_number(
85 clause,
86 self.max_literal_number * number_of_tags,
87 )
88 }
89 }
90
91 pub fn is_cube_initial(&self, cube: &Cube) -> bool {
92 for literal in cube.iter() {
94 if self.initial_literals.contains(&!literal.to_owned()) {
95 return false;
96 }
97 }
98 true
99 }
100
101 pub fn extract_state_from_assignment(&self, assignment: &Assignment) -> Cube {
102 let mut literals = Vec::new();
103
104 for state_lit_num in &self.state_literals {
105 literals.push(
106 Literal::new(state_lit_num.to_owned())
107 .negate_if_true(!assignment.get_value(state_lit_num).unwrap()),
108 )
109 }
110
111 Cube::new(&literals)
112 }
113
114 pub fn extract_input_from_assignment(&self, assignment: &Assignment) -> Cube {
115 let mut literals = Vec::new();
116
117 for input_lit_num in &self.input_literals {
118 literals.push(
119 Literal::new(input_lit_num.to_owned())
120 .negate_if_true(!assignment.get_value(input_lit_num).unwrap()),
121 )
122 }
123
124 Cube::new(&literals)
125 }
126
127 pub fn intersect_cube_with_cone_of_safety(&self, c: &Cube) -> Cube {
128 let filtered_c: Vec<Literal> = c
129 .iter()
130 .filter(|l| self.cone_of_safety_only_latches.contains(&l.get_number()))
131 .map(|l| l.to_owned())
132 .collect();
133 Cube::new(&filtered_c)
134 }
135
136 pub fn intersect_cube_with_cone_of_transition(&self, c: &Cube) -> Cube {
137 let filtered_c: Vec<Literal> = c
138 .iter()
139 .filter(|l| {
140 self.cone_of_transition_only_latches
141 .contains(&l.get_number())
142 })
143 .map(|l| l.to_owned())
144 .collect();
145 Cube::new(&filtered_c)
146 }
147
148 pub fn check_invariant<T: StatelessSatSolver>(&self, inv_candidate: &CNF) {
172 let mut init = self.get_initial_relation().to_cnf();
175 init.append(&self.get_state_to_safety_translation());
176 assert!(
179 does_a_imply_b::<T>(&init, inv_candidate),
180 "Invariant does not cover all of init."
181 );
182
183 let mut a = self.get_transition_relation();
185 a.append(inv_candidate);
186 a.append(&self.get_state_to_safety_translation());
187 a.append(&self.add_tags_to_relation(&self.get_state_to_safety_translation(), 1));
188 let b = self.add_tags_to_relation(inv_candidate, 1);
189 assert!(
190 does_a_imply_b::<T>(&a, &b),
191 "Invariant doesn't cover all of the reachable states."
192 );
193
194 let mut bad = self.get_unsafety_property().to_cnf();
196 bad.append(&self.get_state_to_safety_translation());
197 assert!(
198 !is_a_and_b_satisfiable::<T>(inv_candidate, &bad),
199 "Invariant isn't always safe.",
200 );
201 }
202}