1use crate::prelude::*;
2use crate::verify::verify_equality_by_builtin_rules::objs_equal_by_display_string;
3use std::result::Result;
4
5fn order_split_or_is_exhaustive_pair(a: &AtomicFact, b: &AtomicFact) -> bool {
8 use AtomicFact::*;
9 match (a, b) {
10 (GreaterFact(g), LessEqualFact(le)) => {
11 objs_equal_by_display_string(&g.left, &le.left)
12 && objs_equal_by_display_string(&g.right, &le.right)
13 }
14 (LessFact(l), GreaterEqualFact(ge)) => {
15 objs_equal_by_display_string(&l.left, &ge.left)
16 && objs_equal_by_display_string(&l.right, &ge.right)
17 }
18 (LessEqualFact(le), GreaterFact(g)) => {
19 objs_equal_by_display_string(&le.left, &g.left)
20 && objs_equal_by_display_string(&le.right, &g.right)
21 }
22 (GreaterEqualFact(ge), LessFact(l)) => {
23 objs_equal_by_display_string(&ge.left, &l.left)
24 && objs_equal_by_display_string(&ge.right, &l.right)
25 }
26 _ => false,
27 }
28}
29
30fn obj_is_literal_neg_one_for_abs_or_builtin(obj: &Obj) -> bool {
31 match obj {
32 Obj::Number(n) => n.normalized_value == "-1",
33 _ => false,
34 }
35}
36
37fn obj_is_negation_of_for_abs_or_builtin(obj: &Obj, expected_arg: &Obj) -> bool {
38 match obj {
39 Obj::Mul(m) => {
40 (obj_is_literal_neg_one_for_abs_or_builtin(m.left.as_ref())
41 && objs_equal_by_display_string(m.right.as_ref(), expected_arg))
42 || (obj_is_literal_neg_one_for_abs_or_builtin(m.right.as_ref())
43 && objs_equal_by_display_string(m.left.as_ref(), expected_arg))
44 }
45 _ => false,
46 }
47}
48
49fn abs_sign_split_or_is_exhaustive_pair(a: &AtomicFact, b: &AtomicFact) -> bool {
50 let (AtomicFact::EqualFact(first), AtomicFact::EqualFact(second)) = (a, b) else {
51 return false;
52 };
53 let (arg, first_other) = match (&first.left, &first.right) {
54 (Obj::Abs(abs), other) => (abs.arg.as_ref(), other),
55 (other, Obj::Abs(abs)) => (abs.arg.as_ref(), other),
56 _ => return false,
57 };
58 if !objs_equal_by_display_string(arg, first_other) {
59 return false;
60 }
61 let (second_arg, second_other) = match (&second.left, &second.right) {
62 (Obj::Abs(abs), other) => (abs.arg.as_ref(), other),
63 (other, Obj::Abs(abs)) => (abs.arg.as_ref(), other),
64 _ => return false,
65 };
66 objs_equal_by_display_string(arg, second_arg)
67 && obj_is_negation_of_for_abs_or_builtin(second_other, arg)
68}
69
70impl Runtime {
71 pub fn verify_or_fact(
72 &mut self,
73 or_fact: &OrFact,
74 verify_state: &VerifyState,
75 ) -> Result<StmtResult, RuntimeError> {
76 if let Some(cached_result) =
77 self.verify_fact_from_cache_using_display_string(&or_fact.clone().into())
78 {
79 return Ok(cached_result);
80 }
81
82 if !verify_state.well_defined_already_verified {
83 if let Err(e) = self.verify_or_fact_well_defined(or_fact, verify_state) {
84 return Err({
85 VerifyRuntimeError(RuntimeErrorStruct::new(
86 Some(Fact::from(or_fact.clone()).into_stmt()),
87 String::new(),
88 or_fact.line_file.clone(),
89 Some(e),
90 vec![],
91 ))
92 .into()
93 });
94 }
95 }
96
97 let verify_state_for_children = verify_state.make_state_with_req_ok_set_to_true();
98
99 if or_fact.facts.len() == 2 {
100 if let (
101 AndChainAtomicFact::AtomicFact(first_atomic),
102 AndChainAtomicFact::AtomicFact(second_atomic),
103 ) = (&or_fact.facts[0], &or_fact.facts[1])
104 {
105 if first_atomic.make_reversed().to_string() == second_atomic.to_string() {
106 return Ok(
107 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
108 or_fact.clone().into(),
109 "or: complementary atomic facts (make_reversed first equals second)"
110 .to_string(),
111 Vec::new(),
112 ))
113 .into(),
114 );
115 }
116 if order_split_or_is_exhaustive_pair(first_atomic, second_atomic)
117 || order_split_or_is_exhaustive_pair(second_atomic, first_atomic)
118 {
119 return Ok(
120 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
121 or_fact.clone().into(),
122 "or: complementary order relations (strict vs non-strict) on the same terms"
123 .to_string(),
124 Vec::new(),
125 ))
126 .into(),
127 );
128 }
129 if abs_sign_split_or_is_exhaustive_pair(first_atomic, second_atomic)
130 || abs_sign_split_or_is_exhaustive_pair(second_atomic, first_atomic)
131 {
132 return Ok(
133 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
134 or_fact.clone().into(),
135 "or: abs(x) is x or -x".to_string(),
136 Vec::new(),
137 ))
138 .into(),
139 );
140 }
141 }
142 }
143
144 for fact in or_fact.facts.iter() {
145 let result = self.verify_and_chain_atomic_fact(fact, &verify_state_for_children)?;
146 if result.is_true() {
147 return Ok(
148 (FactualStmtSuccess::new_with_verified_by_known_fact_source_recording_facts(
149 or_fact.clone().into(),
150 fact.to_string(),
151 None,
152 Some(fact.line_file()),
153 Vec::new(),
154 ))
155 .into(),
156 );
157 }
158 }
159
160 let result = self.verify_or_fact_with_known_or_facts(or_fact)?;
161 if result.is_true() {
162 return Ok(result);
163 }
164
165 let result = self.verify_or_fact_with_known_forall(or_fact, verify_state)?;
166 if result.is_true() {
167 return Ok(result);
168 }
169
170 Ok((StmtUnknown::new()).into())
171 }
172
173 pub fn verify_or_fact_with_known_or_facts(
174 &mut self,
175 or_fact: &OrFact,
176 ) -> Result<StmtResult, RuntimeError> {
177 let args_in_or_fact = or_fact.get_args_from_fact();
178 let mut all_objs_equal_to_each_arg: Vec<Vec<String>> = Vec::new();
179 for arg in args_in_or_fact.iter() {
180 let mut all_objs_equal_to_current_arg =
181 self.get_all_objs_equal_to_given(&arg.to_string());
182 if all_objs_equal_to_current_arg.is_empty() {
183 all_objs_equal_to_current_arg.push(arg.to_string());
184 }
185 all_objs_equal_to_each_arg.push(all_objs_equal_to_current_arg);
186 }
187
188 for environment in self.iter_environments_from_top() {
189 let result = Self::verify_or_fact_with_known_or_facts_with_facts_in_environment(
190 environment,
191 or_fact,
192 &all_objs_equal_to_each_arg,
193 )?;
194 if result.is_true() {
195 return Ok(result);
196 }
197 }
198
199 Ok((StmtUnknown::new()).into())
200 }
201
202 pub fn verify_or_fact_with_known_or_facts_with_facts_in_environment(
203 environment: &Environment,
204 or_fact: &OrFact,
205 all_objs_equal_to_each_arg: &Vec<Vec<String>>,
206 ) -> Result<StmtResult, RuntimeError> {
207 if let Some(known_or_facts) = environment.known_or_facts.get(&or_fact.key()) {
208 for known_or_fact in known_or_facts.iter() {
209 let result = Self::_verify_or_fact_the_same_type_and_return_matched_args(
210 known_or_fact,
211 or_fact,
212 )?;
213 let mut all_args_match = true;
214 if let Some(matched_args) = result {
215 for (index, matched_arg) in matched_args.iter().enumerate() {
216 let known_arg_string = matched_arg.0.to_string();
217
218 if known_arg_string != matched_arg.1.to_string()
219 && !all_objs_equal_to_each_arg[index].contains(&known_arg_string)
220 {
221 all_args_match = false;
222 break;
223 }
224 }
225 }
226
227 if all_args_match {
228 return Ok((FactualStmtSuccess::new_with_verified_by_known_fact_source_recording_facts(
229 or_fact.clone().into(),
230 known_or_fact.to_string(),
231 Some(known_or_fact.clone().into()),
232 None,
233 Vec::new(),
234 )).into());
235 }
236 }
237 }
238
239 return Ok((StmtUnknown::new()).into());
240 }
241}