1use crate::prelude::*;
2use std::collections::HashMap;
3use std::rc::Rc;
4use std::result::Result;
5
6impl Runtime {
9 pub fn verify_exist_fact_with_known_forall(
10 &mut self,
11 exist_fact: &ExistFactEnum,
12 verify_state: &VerifyState,
13 ) -> Result<StmtResult, RuntimeError> {
14 if let Some(fact_verified) =
15 self.try_verify_exist_fact_with_known_forall_facts_in_envs(exist_fact, verify_state)?
16 {
17 return Ok((fact_verified).into());
18 }
19 Ok((StmtUnknown::new()).into())
20 }
21
22 fn get_matched_exist_fact_in_known_forall_fact_in_envs(
23 &mut self,
24 iterate_from_env_index: usize,
25 iterate_from_known_forall_fact_index: usize,
26 given_exist_fact: &ExistFactEnum,
27 ) -> Result<
28 (
29 (usize, usize),
30 Option<HashMap<String, Obj>>,
31 Option<(ExistFactEnum, Rc<KnownForallFactParamsAndDom>)>,
32 ),
33 RuntimeError,
34 > {
35 let lookup_keys = known_exist_lookup_keys_for_forall_bucket(given_exist_fact);
36
37 let envs_count = self.environment_stack.len();
38 for i in iterate_from_env_index..envs_count {
39 let env = &self.environment_stack[envs_count - 1 - i];
40 let mut merged_bucket: Vec<(ExistFactEnum, Rc<KnownForallFactParamsAndDom>)> =
41 Vec::new();
42 for lk in lookup_keys.iter() {
43 if let Some(known_forall_facts_in_env) =
44 env.known_exist_facts_in_forall_facts.get(lk.as_str())
45 {
46 merged_bucket.extend(known_forall_facts_in_env.iter().cloned());
47 }
48 }
49 merged_bucket.sort_by(|a, b| a.0.to_string().cmp(&b.0.to_string()));
50 merged_bucket.dedup_by(|a, b| a.0.to_string() == b.0.to_string());
51 if !merged_bucket.is_empty() {
52 let known_forall_facts_count = merged_bucket.len();
53 for j in iterate_from_known_forall_fact_index..known_forall_facts_count {
54 let entry_idx = known_forall_facts_count - 1 - j;
55 let (fact_args_in_known_forall, given_fact_args, current_known_forall) = {
56 let current_known_forall = &merged_bucket[entry_idx];
57 (
58 current_known_forall.0.get_args_from_fact(),
59 given_exist_fact.get_args_from_fact(),
60 current_known_forall.clone(),
61 )
62 };
63 let match_result = self
64 .match_args_in_fact_in_known_forall_fact_with_given_args(
65 &fact_args_in_known_forall,
66 &given_fact_args,
67 )?;
68 if let Some(arg_map) = match_result {
69 let exist_in_forall = ¤t_known_forall.0;
70 if !exist_in_forall.can_be_used_to_verify_goal(given_exist_fact) {
71 continue;
72 }
73 return Ok(((i, j), Some(arg_map), Some(current_known_forall)));
74 }
75 }
76 }
77 }
78
79 Ok(((0, 0), None, None))
80 }
81
82 fn try_verify_exist_fact_with_known_forall_facts_in_envs(
83 &mut self,
84 exist_fact: &ExistFactEnum,
85 verify_state: &VerifyState,
86 ) -> Result<Option<FactualStmtSuccess>, RuntimeError> {
87 let mut iterate_from_env_index = 0;
88 let mut iterate_from_known_forall_fact_index = 0;
89
90 loop {
91 let result = self.get_matched_exist_fact_in_known_forall_fact_in_envs(
92 iterate_from_env_index,
93 iterate_from_known_forall_fact_index,
94 exist_fact,
95 )?;
96 let ((i, j), arg_map_opt, known_forall_opt) = result;
97 match (arg_map_opt, known_forall_opt) {
98 (Some(arg_map), Some((exist_fact_in_known_forall, forall_rc))) => {
99 if let Some(fact_verified) = self
100 .verify_exist_fact_args_satisfy_forall_requirements(
101 &exist_fact_in_known_forall,
102 &forall_rc,
103 arg_map,
104 exist_fact,
105 verify_state,
106 )?
107 {
108 return Ok(Some(fact_verified));
109 }
110 iterate_from_env_index = i;
111 iterate_from_known_forall_fact_index = j + 1;
112 }
113 _ => return Ok(None),
114 }
115 }
116 }
117
118 fn verify_exist_fact_args_satisfy_forall_requirements(
119 &mut self,
120 exist_fact_in_known_forall: &ExistFactEnum,
121 known_forall: &Rc<KnownForallFactParamsAndDom>,
122 arg_map: HashMap<String, Obj>,
123 given_exist_fact: &ExistFactEnum,
124 verify_state: &VerifyState,
125 ) -> Result<Option<FactualStmtSuccess>, RuntimeError> {
126 if !exist_fact_in_known_forall.can_be_used_to_verify_goal(given_exist_fact) {
127 return Ok(None);
128 }
129 let given_exist_param_names = given_exist_fact
131 .params_def_with_type()
132 .collect_param_names();
133
134 let known_exist_param_names = exist_fact_in_known_forall
135 .params_def_with_type()
136 .collect_param_names();
137 if !known_exist_param_names
138 .iter()
139 .all(|param_name| arg_map.contains_key(param_name))
140 {
141 return Ok(None);
142 }
143
144 if given_exist_param_names.len() != known_exist_param_names.len() {
145 return Ok(None);
146 }
147
148 let mut known_exist_params_to_given_exist_params_map: Vec<Obj> = Vec::new();
149 for (known_param_name, given_param_name) in known_exist_param_names
150 .iter()
151 .zip(given_exist_param_names.iter())
152 {
153 let obj = match arg_map.get(known_param_name) {
154 Some(v) => {
155 if !Self::obj_matches_exist_forall_binding_name(v, given_param_name) {
156 return Ok(None);
157 }
158 v
159 }
160 None => return Ok(None),
161 };
162 known_exist_params_to_given_exist_params_map.push(obj.clone());
163 }
164
165 for (key, obj) in arg_map.iter() {
167 if let Some(spine) = Self::obj_binding_spine_name_for_arg_map(obj) {
168 if given_exist_param_names.iter().any(|n| n == spine) {
169 if !known_exist_param_names.contains(key) {
170 return Ok(None);
171 }
172 }
173 }
174 }
175
176 let param_names = known_forall.params_def.collect_param_names();
178
179 if !param_names
180 .iter()
181 .all(|param_name| arg_map.contains_key(param_name))
182 {
183 return Ok(None);
184 }
185
186 let mut args_for_params: Vec<Obj> = Vec::new();
187
188 for param_name in param_names.iter() {
189 let obj = match arg_map.get(param_name) {
190 Some(v) => v,
191 None => return Ok(None),
192 };
193 if Self::obj_depends_on_given_exist_param(obj, &given_exist_param_names) {
194 return Ok(None);
195 }
196
197 args_for_params.push(obj.clone());
198 }
199
200 let args_param_types = self
201 .verify_args_satisfy_param_def_flat_types(
202 &known_forall.params_def,
203 &args_for_params,
204 verify_state,
205 ParamObjType::Forall,
206 )
207 .map_err(|e| {
208 {
209 RuntimeError::from(VerifyRuntimeError(RuntimeErrorStruct::new(
210 Some(Fact::from(given_exist_fact.clone()).into_stmt()),
211 String::new(),
212 given_exist_fact.line_file(),
213 Some(e),
214 vec![],
215 )))
216 }
217 })?;
218 if args_param_types.is_unknown() {
219 return Ok(None);
220 }
221
222 let param_to_arg_map = match known_forall
223 .params_def
224 .param_def_params_to_arg_map(&arg_map)
225 {
226 Some(m) => m,
227 None => return Ok(None),
228 };
229
230 for dom_fact in known_forall.dom.iter() {
231 let instantiated_dom_fact = self
232 .inst_fact(dom_fact, ¶m_to_arg_map, ParamObjType::Forall, None)
233 .map_err(|e| {
234 {
235 RuntimeError::from(VerifyRuntimeError(RuntimeErrorStruct::new(
236 Some(Fact::from(given_exist_fact.clone()).into_stmt()),
237 String::new(),
238 given_exist_fact.line_file(),
239 Some(e),
240 vec![],
241 )))
242 }
243 })?;
244 let result = self
245 .verify_fact(&instantiated_dom_fact, verify_state)
246 .map_err(|e| {
247 {
248 RuntimeError::from(VerifyRuntimeError(RuntimeErrorStruct::new(
249 Some(Fact::from(given_exist_fact.clone()).into_stmt()),
250 String::new(),
251 given_exist_fact.line_file(),
252 Some(e),
253 vec![],
254 )))
255 }
256 })?;
257 if result.is_unknown() {
258 return Ok(None);
259 }
260 }
261
262 let verified_by_known_forall_fact = ForallFact::new(
263 known_forall.params_def.clone(),
264 known_forall.dom.clone(),
265 vec![exist_fact_in_known_forall.clone().into()],
266 known_forall.line_file.clone(),
267 )?;
268 let fact_verified = FactualStmtSuccess::new_with_verified_by_known_fact(
269 given_exist_fact.clone().into(),
270 VerifiedByResult::cited_fact(
271 given_exist_fact.clone().into(),
272 verified_by_known_forall_fact.clone().into(),
273 None,
274 ),
275 Vec::new(),
276 );
277 Ok(Some(fact_verified))
278 }
279
280 fn obj_binding_spine_name_for_arg_map(obj: &Obj) -> Option<&str> {
281 match obj {
282 Obj::Atom(AtomObj::Exist(p)) => Some(p.name.as_str()),
283 Obj::Atom(AtomObj::Forall(p)) => Some(p.name.as_str()),
284 Obj::Atom(AtomObj::FnSet(p)) => Some(p.name.as_str()),
285 Obj::Atom(AtomObj::Def(p)) => Some(p.name.as_str()),
286 Obj::Atom(AtomObj::SetBuilder(p)) => Some(p.name.as_str()),
287 Obj::Atom(AtomObj::Induc(p)) => Some(p.name.as_str()),
288 Obj::Atom(AtomObj::DefAlgo(p)) => Some(p.name.as_str()),
289 _ => None,
290 }
291 }
292
293 fn obj_matches_exist_forall_binding_name(obj: &Obj, name: &str) -> bool {
294 match obj {
295 Obj::Atom(AtomObj::Exist(p)) => p.name == name,
296 Obj::Atom(AtomObj::Forall(p)) => p.name == name,
297 Obj::Atom(AtomObj::FnSet(p)) => p.name == name,
298 Obj::Atom(AtomObj::Def(p)) => p.name == name,
299 Obj::Atom(AtomObj::SetBuilder(p)) => p.name == name,
300 Obj::Atom(AtomObj::Induc(p)) => p.name == name,
301 Obj::Atom(AtomObj::DefAlgo(p)) => p.name == name,
302 _ => obj.to_string() == name,
303 }
304 }
305
306 fn obj_depends_on_given_exist_param(obj: &Obj, names: &[String]) -> bool {
307 match obj {
308 Obj::Atom(AtomObj::Exist(p)) => names.iter().any(|name| name == &p.name),
309 Obj::Atom(_) | Obj::Number(_) | Obj::StandardSet(_) => false,
310 Obj::Add(x) => Self::obj_pair_depends_on_given_exist_param(
311 x.left.as_ref(),
312 x.right.as_ref(),
313 names,
314 ),
315 Obj::Sub(x) => Self::obj_pair_depends_on_given_exist_param(
316 x.left.as_ref(),
317 x.right.as_ref(),
318 names,
319 ),
320 Obj::Mul(x) => Self::obj_pair_depends_on_given_exist_param(
321 x.left.as_ref(),
322 x.right.as_ref(),
323 names,
324 ),
325 Obj::Div(x) => Self::obj_pair_depends_on_given_exist_param(
326 x.left.as_ref(),
327 x.right.as_ref(),
328 names,
329 ),
330 Obj::Mod(x) => Self::obj_pair_depends_on_given_exist_param(
331 x.left.as_ref(),
332 x.right.as_ref(),
333 names,
334 ),
335 Obj::Pow(x) => Self::obj_pair_depends_on_given_exist_param(
336 x.base.as_ref(),
337 x.exponent.as_ref(),
338 names,
339 ),
340 Obj::Max(x) => Self::obj_pair_depends_on_given_exist_param(
341 x.left.as_ref(),
342 x.right.as_ref(),
343 names,
344 ),
345 Obj::Min(x) => Self::obj_pair_depends_on_given_exist_param(
346 x.left.as_ref(),
347 x.right.as_ref(),
348 names,
349 ),
350 Obj::Union(x) => Self::obj_pair_depends_on_given_exist_param(
351 x.left.as_ref(),
352 x.right.as_ref(),
353 names,
354 ),
355 Obj::Intersect(x) => Self::obj_pair_depends_on_given_exist_param(
356 x.left.as_ref(),
357 x.right.as_ref(),
358 names,
359 ),
360 Obj::SetMinus(x) => Self::obj_pair_depends_on_given_exist_param(
361 x.left.as_ref(),
362 x.right.as_ref(),
363 names,
364 ),
365 Obj::SetDiff(x) => Self::obj_pair_depends_on_given_exist_param(
366 x.left.as_ref(),
367 x.right.as_ref(),
368 names,
369 ),
370 Obj::MatrixAdd(x) => Self::obj_pair_depends_on_given_exist_param(
371 x.left.as_ref(),
372 x.right.as_ref(),
373 names,
374 ),
375 Obj::MatrixSub(x) => Self::obj_pair_depends_on_given_exist_param(
376 x.left.as_ref(),
377 x.right.as_ref(),
378 names,
379 ),
380 Obj::MatrixMul(x) => Self::obj_pair_depends_on_given_exist_param(
381 x.left.as_ref(),
382 x.right.as_ref(),
383 names,
384 ),
385 Obj::MatrixScalarMul(x) => Self::obj_pair_depends_on_given_exist_param(
386 x.scalar.as_ref(),
387 x.matrix.as_ref(),
388 names,
389 ),
390 Obj::MatrixPow(x) => Self::obj_pair_depends_on_given_exist_param(
391 x.base.as_ref(),
392 x.exponent.as_ref(),
393 names,
394 ),
395 Obj::Log(x) => {
396 Self::obj_pair_depends_on_given_exist_param(x.base.as_ref(), x.arg.as_ref(), names)
397 }
398 Obj::Range(x) => {
399 Self::obj_pair_depends_on_given_exist_param(x.start.as_ref(), x.end.as_ref(), names)
400 }
401 Obj::ClosedRange(x) => {
402 Self::obj_pair_depends_on_given_exist_param(x.start.as_ref(), x.end.as_ref(), names)
403 }
404 Obj::FnRange(x) => Self::obj_depends_on_given_exist_param(x.fn_obj.as_ref(), names),
405 Obj::FnDom(x) => Self::obj_depends_on_given_exist_param(x.fn_obj.as_ref(), names),
406 Obj::Proj(x) => {
407 Self::obj_pair_depends_on_given_exist_param(x.set.as_ref(), x.dim.as_ref(), names)
408 }
409 Obj::FiniteSeqSet(x) => {
410 Self::obj_pair_depends_on_given_exist_param(x.set.as_ref(), x.n.as_ref(), names)
411 }
412 Obj::MatrixSet(x) => {
413 Self::obj_depends_on_given_exist_param(x.set.as_ref(), names)
414 || Self::obj_depends_on_given_exist_param(x.row_len.as_ref(), names)
415 || Self::obj_depends_on_given_exist_param(x.col_len.as_ref(), names)
416 }
417 Obj::ObjAtIndex(x) => {
418 Self::obj_pair_depends_on_given_exist_param(x.obj.as_ref(), x.index.as_ref(), names)
419 }
420 Obj::Abs(x) => Self::obj_depends_on_given_exist_param(x.arg.as_ref(), names),
421 Obj::Cup(x) => Self::obj_depends_on_given_exist_param(x.left.as_ref(), names),
422 Obj::Cap(x) => Self::obj_depends_on_given_exist_param(x.left.as_ref(), names),
423 Obj::PowerSet(x) => Self::obj_depends_on_given_exist_param(x.set.as_ref(), names),
424 Obj::CartDim(x) => Self::obj_depends_on_given_exist_param(x.set.as_ref(), names),
425 Obj::TupleDim(x) => Self::obj_depends_on_given_exist_param(x.arg.as_ref(), names),
426 Obj::Count(x) => Self::obj_depends_on_given_exist_param(x.set.as_ref(), names),
427 Obj::SeqSet(x) => Self::obj_depends_on_given_exist_param(x.set.as_ref(), names),
428 Obj::Choose(x) => Self::obj_depends_on_given_exist_param(x.set.as_ref(), names),
429 Obj::Sum(x) => {
430 Self::obj_depends_on_given_exist_param(x.start.as_ref(), names)
431 || Self::obj_depends_on_given_exist_param(x.end.as_ref(), names)
432 || Self::obj_depends_on_given_exist_param(x.func.as_ref(), names)
433 }
434 Obj::Product(x) => {
435 Self::obj_depends_on_given_exist_param(x.start.as_ref(), names)
436 || Self::obj_depends_on_given_exist_param(x.end.as_ref(), names)
437 || Self::obj_depends_on_given_exist_param(x.func.as_ref(), names)
438 }
439 Obj::ListSet(x) => Self::obj_list_depends_on_given_exist_param(&x.list, names),
440 Obj::Cart(x) => Self::obj_list_depends_on_given_exist_param(&x.args, names),
441 Obj::Tuple(x) => Self::obj_list_depends_on_given_exist_param(&x.args, names),
442 Obj::FiniteSeqListObj(x) => Self::obj_list_depends_on_given_exist_param(&x.objs, names),
443 Obj::MatrixListObj(x) => x.rows.iter().any(|row| {
444 row.iter()
445 .any(|obj| Self::obj_depends_on_given_exist_param(obj.as_ref(), names))
446 }),
447 Obj::FamilyObj(x) => x
448 .params
449 .iter()
450 .any(|obj| Self::obj_depends_on_given_exist_param(obj, names)),
451 Obj::StructObj(x) => x
452 .params
453 .iter()
454 .any(|obj| Self::obj_depends_on_given_exist_param(obj, names)),
455 Obj::ObjAsStructInstanceWithFieldAccess(x) => {
456 x.struct_obj
457 .params
458 .iter()
459 .any(|obj| Self::obj_depends_on_given_exist_param(obj, names))
460 || Self::obj_depends_on_given_exist_param(x.obj.as_ref(), names)
461 }
462 Obj::SetBuilder(x) => {
463 Self::obj_depends_on_given_exist_param(x.param_set.as_ref(), names)
464 || x.facts.iter().any(|fact| {
465 Self::or_and_chain_fact_depends_on_given_exist_param(fact, names)
466 })
467 }
468 Obj::FnSet(x) => Self::fn_set_body_depends_on_given_exist_param(&x.body, names),
469 Obj::AnonymousFn(x) => {
470 Self::fn_set_body_depends_on_given_exist_param(&x.body, names)
471 || Self::obj_depends_on_given_exist_param(x.equal_to.as_ref(), names)
472 }
473 Obj::FnObj(x) => {
474 Self::fn_obj_head_depends_on_given_exist_param(x.head.as_ref(), names)
475 || x.body.iter().any(|args| {
476 args.iter()
477 .any(|arg| Self::obj_depends_on_given_exist_param(arg.as_ref(), names))
478 })
479 }
480 }
481 }
482
483 fn obj_pair_depends_on_given_exist_param(left: &Obj, right: &Obj, names: &[String]) -> bool {
484 Self::obj_depends_on_given_exist_param(left, names)
485 || Self::obj_depends_on_given_exist_param(right, names)
486 }
487
488 fn obj_list_depends_on_given_exist_param(objs: &[Box<Obj>], names: &[String]) -> bool {
489 objs.iter()
490 .any(|obj| Self::obj_depends_on_given_exist_param(obj.as_ref(), names))
491 }
492
493 fn fn_set_body_depends_on_given_exist_param(body: &FnSetBody, names: &[String]) -> bool {
494 body.params_def_with_set.iter().any(|param_group| {
495 Self::param_group_with_set_depends_on_given_exist_param(param_group, names)
496 }) || body
497 .dom_facts
498 .iter()
499 .any(|fact| Self::or_and_chain_fact_depends_on_given_exist_param(fact, names))
500 || Self::obj_depends_on_given_exist_param(body.ret_set.as_ref(), names)
501 }
502
503 fn fn_obj_head_depends_on_given_exist_param(head: &FnObjHead, names: &[String]) -> bool {
504 match head {
505 FnObjHead::Exist(p) => names.iter().any(|name| name == &p.name),
506 FnObjHead::AnonymousFnLiteral(x) => {
507 Self::fn_set_body_depends_on_given_exist_param(&x.body, names)
508 || Self::obj_depends_on_given_exist_param(x.equal_to.as_ref(), names)
509 }
510 _ => false,
511 }
512 }
513
514 fn param_group_with_set_depends_on_given_exist_param(
515 param_group: &ParamGroupWithSet,
516 names: &[String],
517 ) -> bool {
518 Self::obj_depends_on_given_exist_param(param_group.set_obj(), names)
519 }
520
521 fn or_and_chain_fact_depends_on_given_exist_param(
522 fact: &OrAndChainAtomicFact,
523 names: &[String],
524 ) -> bool {
525 fact.get_args_from_fact()
526 .iter()
527 .any(|obj| Self::obj_depends_on_given_exist_param(obj, names))
528 }
529}
530
531fn known_exist_lookup_keys_for_forall_bucket(goal: &ExistFactEnum) -> Vec<String> {
532 let mut keys = vec![goal.alpha_normalized_key(), goal.key()];
533 if let ExistFactEnum::ExistFact(body) = goal {
534 let unique = ExistFactEnum::ExistUniqueFact(body.clone());
535 keys.push(unique.alpha_normalized_key());
536 keys.push(unique.key());
537 }
538 keys.sort();
539 keys.dedup();
540 keys
541}
542
543#[cfg(test)]
544mod tests {
545 use super::*;
546
547 #[test]
548 fn detects_nested_exist_witness_dependency() {
549 let names = vec!["x".to_string()];
550 let witness: Obj = ExistFreeParamObj::new("x".to_string()).into();
551 let external: Obj = Identifier::new("a".to_string()).into();
552 let nested: Obj = Union::new(witness, external.clone()).into();
553
554 assert!(Runtime::obj_depends_on_given_exist_param(&nested, &names));
555 assert!(!Runtime::obj_depends_on_given_exist_param(
556 &external, &names
557 ));
558 }
559
560 #[test]
561 fn detects_function_call_on_exist_witness() {
562 let names = vec!["x".to_string()];
563 let head: FnObjHead = ExistFreeParamObj::new("x".to_string()).into();
564 let arg: Obj = Number::new("1".to_string()).into();
565 let fn_obj: Obj = FnObj::new(head, vec![vec![Box::new(arg)]]).into();
566
567 assert!(Runtime::obj_depends_on_given_exist_param(&fn_obj, &names));
568 }
569}