1use crate::prelude::*;
2use crate::stmt::definition_stmt::induc_obj_plus_offset;
3
4impl Runtime {
5 pub fn exec_have_fn_by_induc(
6 &mut self,
7 stmt: &HaveFnByInducStmt,
8 ) -> Result<StmtResult, RuntimeError> {
9 self.run_in_local_env(|rt| rt.exec_have_fn_by_induc_verify_process(stmt))?;
10
11 let infer_result = self.exec_have_fn_by_induc_store_process(stmt)?;
12
13 Ok((NonFactualStmtSuccess::new(stmt.clone().into(), infer_result, vec![])).into())
14 }
15
16 fn exec_have_fn_by_induc_verify_process(
17 &mut self,
18 stmt: &HaveFnByInducStmt,
19 ) -> Result<(), RuntimeError> {
20 for special_case_equal_to in stmt.special_cases_equal_tos.iter() {
21 self.verify_obj_well_defined_and_store_cache(
22 special_case_equal_to,
23 &VerifyState::new(0, false),
24 )?;
25 }
26
27 self.run_in_local_env(|rt| rt.exec_have_fn_by_induc_verify_last_case(stmt))?;
28
29 Ok(())
30 }
31
32 fn have_fn_by_induc_err(stmt: &HaveFnByInducStmt, cause: RuntimeError) -> RuntimeError {
33 exec_stmt_error_with_stmt_and_cause(stmt.clone().into(), cause)
34 }
35
36 fn have_fn_by_induc_verify_last_case_register_fn(
39 &mut self,
40 stmt: &HaveFnByInducStmt,
41 param_name: &str,
42 ) -> Result<(), RuntimeError> {
43 self.store_free_param_or_identifier_name(&stmt.name, ParamObjType::Identifier)?;
44
45 let random_param = self.generate_random_unused_name();
46
47 let induc_outer_param =
48 obj_for_bound_param_in_scope(param_name.to_string(), ParamObjType::Induc);
49 let dom_facts: Vec<OrAndChainAtomicFact> = vec![
50 GreaterEqualFact::new(
51 obj_for_bound_param_in_scope(random_param.clone(), ParamObjType::FnSet),
52 stmt.induc_from.clone(),
53 stmt.line_file.clone(),
54 )
55 .into(),
56 LessFact::new(
57 obj_for_bound_param_in_scope(random_param.clone(), ParamObjType::FnSet),
58 induc_outer_param,
59 stmt.line_file.clone(),
60 )
61 .into(),
62 ];
63
64 let fn_set = self.new_fn_set(
65 vec![ParamGroupWithSet::new(
66 vec![random_param.clone()],
67 StandardSet::Z.into(),
68 )],
69 dom_facts,
70 stmt.ret_set.clone(),
71 )?;
72
73 let function_in_function_set_fact: Fact = InFact::new(
74 Identifier::new(stmt.name.clone()).into(),
75 fn_set.into(),
76 stmt.line_file.clone(),
77 )
78 .into();
79
80 self.verify_well_defined_and_store_and_infer_with_default_verify_state(
81 function_in_function_set_fact,
82 )
83 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
84
85 Ok(())
86 }
87
88 fn have_fn_by_induc_verify_one_equal_to_well_defined(
89 &mut self,
90 stmt: &HaveFnByInducStmt,
91 equal_to: &Obj,
92 verify_state: &VerifyState,
93 ) -> Result<(), RuntimeError> {
94 self.verify_obj_well_defined_and_store_cache(equal_to, verify_state)
95 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
96
97 let equal_to_in_ret_set_atomic_fact: AtomicFact = InFact::new(
98 equal_to.clone(),
99 stmt.ret_set.clone(),
100 stmt.line_file.clone(),
101 )
102 .into();
103 let verify_result = self
104 .verify_atomic_fact(&equal_to_in_ret_set_atomic_fact, verify_state)
105 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
106 if verify_result.is_unknown() {
107 return Err(short_exec_error(
108 stmt.clone().into(),
109 format!(
110 "have_fn_by_induc: {} is not in return set {}",
111 equal_to, stmt.ret_set
112 ),
113 None,
114 vec![],
115 ));
116 }
117 Ok(())
118 }
119
120 fn exec_have_fn_by_induc_verify_last_case(
127 &mut self,
128 stmt: &HaveFnByInducStmt,
129 ) -> Result<(), RuntimeError> {
130 let verify_state = VerifyState::new(0, false);
131 let n = stmt.special_cases_equal_tos.len();
132 let line_file = stmt.line_file.clone();
133
134 let param_name_str = stmt.param.clone();
135
136 let left_id: Obj =
137 obj_for_bound_param_in_scope(param_name_str.clone(), ParamObjType::Induc);
138
139 self.store_free_param_or_identifier_name(¶m_name_str, ParamObjType::Induc)?;
140
141 self.define_parameter_by_binding_param_type(
142 ¶m_name_str,
143 &ParamType::Obj(StandardSet::Z.into()),
144 ParamObjType::Induc,
145 )?;
146
147 let param_larger_than_induc_plus_offset: AndChainAtomicFact = GreaterEqualFact::new(
148 left_id,
149 induc_obj_plus_offset(&stmt.induc_from, n),
150 line_file.clone(),
151 )
152 .into();
153
154 self.verify_well_defined_and_store_and_infer_with_default_verify_state(
155 param_larger_than_induc_plus_offset.into(),
156 )
157 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
158
159 for i in 1..=n {
161 let arg: Obj = Sub::new(
162 obj_for_bound_param_in_scope(param_name_str.clone(), ParamObjType::Induc),
163 i.into(),
164 )
165 .into();
166 let fn_obj: Obj = FnObj::new(
167 FnObjHead::Identifier(Identifier::new(stmt.name.clone())),
168 vec![vec![Box::new(arg.clone())]],
169 )
170 .into();
171 self.store_well_defined_obj_cache(&fn_obj);
172 let fn_in_ret: Fact =
173 InFact::new(fn_obj, stmt.ret_set.clone(), line_file.clone()).into();
174 self.verify_well_defined_and_store_and_infer_with_default_verify_state(fn_in_ret)
175 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
176 }
177
178 self.have_fn_by_induc_verify_last_case_register_fn(stmt, ¶m_name_str)?;
179
180 match &stmt.last_case {
181 HaveFnByInducLastCase::EqualTo(eq) => {
182 self.have_fn_by_induc_verify_one_equal_to_well_defined(stmt, eq, &verify_state)?;
183 }
184 HaveFnByInducLastCase::NestedCases(last_pairs) if !last_pairs.is_empty() => {
185 let coverage_cases: Vec<AndChainAtomicFact> =
186 last_pairs.iter().map(|c| c.case_fact.clone()).collect();
187 let coverage: Fact = OrFact::new(coverage_cases, line_file.clone()).into();
188 self.verify_fact_return_err_if_not_true(&coverage, &verify_state)
189 .map_err(|e| {
190 short_exec_error(
191 stmt.clone().into(),
192 "have_fn_by_induc: nested last cases do not cover all situations"
193 .to_string(),
194 Some(e),
195 vec![],
196 )
197 })?;
198
199 for nested in last_pairs.iter() {
200 self.run_in_local_env(|rt| {
201 rt.verify_well_defined_and_store_and_infer_with_default_verify_state(
202 nested.case_fact.clone().into(),
203 )
204 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
205 rt.have_fn_by_induc_verify_one_equal_to_well_defined(
206 stmt,
207 &nested.equal_to,
208 &verify_state,
209 )
210 })?;
211 }
212 }
213 HaveFnByInducLastCase::NestedCases(_) => {
214 return Err(short_exec_error(
215 stmt.clone().into(),
216 "have_fn_by_induc: nested last case list must not be empty".to_string(),
217 None,
218 vec![],
219 ));
220 }
221 }
222
223 Ok(())
224 }
225
226 fn merge_store_infer_with_fallback_fact(
228 infer_result: &mut InferResult,
229 store_infer: InferResult,
230 fallback_fact: &Fact,
231 ) {
232 let empty = store_infer.is_empty();
233 infer_result.new_infer_result_inside(store_infer);
234 if empty {
235 infer_result.new_fact(fallback_fact);
236 }
237 }
238
239 fn exec_have_fn_by_induc_store_process(
240 &mut self,
241 stmt: &HaveFnByInducStmt,
242 ) -> Result<InferResult, RuntimeError> {
243 let in_fact: AtomicFact = InFact::new(
245 stmt.induc_from.clone(),
246 StandardSet::Z.into(),
247 stmt.line_file.clone(),
248 )
249 .into();
250 let verify_result = self
251 .verify_atomic_fact(&in_fact, &VerifyState::new(0, false))
252 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
253 if verify_result.is_unknown() {
254 return Err(short_exec_error(
255 stmt.clone().into(),
256 "have_fn_by_induc: induc_from is not in Z".to_string(),
257 None,
258 vec![],
259 ));
260 }
261
262 let mut infer_result = InferResult::new();
263 let fs = self.fn_set_from_fn_set_clause(&stmt.fn_user_fn_set_clause())?;
264
265 self.store_free_param_or_identifier_name(&stmt.name, ParamObjType::Identifier)?;
268
269 let bind_infer = self.define_parameter_by_binding_param_type(
270 &stmt.name,
271 &ParamType::Obj(fs.clone().into()),
272 ParamObjType::Identifier,
273 )?;
274 let bind_fact: Fact = InFact::new(
275 Identifier::new(stmt.name.clone()).into(),
276 fs.clone().into(),
277 stmt.line_file.clone(),
278 )
279 .into();
280 Self::merge_store_infer_with_fallback_fact(&mut infer_result, bind_infer, &bind_fact);
281
282 for i in 0..stmt.special_cases_equal_tos.len() {
284 let raw_arg = if i == 0 {
285 stmt.induc_from.clone()
286 } else {
287 Add::new(stmt.induc_from.clone(), i.into()).into()
288 };
289 let arg = raw_arg.replace_with_numeric_result_if_can_be_calculated().0;
291
292 let equal_to = &stmt.special_cases_equal_tos[i];
293
294 let fn_obj: Obj = FnObj::new(
295 FnObjHead::Identifier(Identifier::new(stmt.name.clone())),
296 vec![vec![Box::new(arg.clone())]],
297 )
298 .into();
299
300 let equal_fact: Fact =
301 EqualFact::new(fn_obj.clone(), equal_to.clone(), stmt.line_file.clone()).into();
302
303 let result = self
304 .verify_well_defined_and_store_and_infer_with_default_verify_state(
305 equal_fact.clone(),
306 )
307 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
308
309 Self::merge_store_infer_with_fallback_fact(&mut infer_result, result, &equal_fact);
310 }
311
312 match &stmt.last_case {
313 HaveFnByInducLastCase::EqualTo(eq) => {
314 let param_name = stmt.param.clone();
315 let param_def = vec![ParamGroupWithParamType::new(
316 vec![param_name.clone()],
317 ParamType::Obj(StandardSet::Z.into()),
318 )];
319
320 let mut dom: Vec<Fact> = stmt.forall_fn_base_dom_exist_or_facts();
321
322 let induc_plus_n =
323 induc_obj_plus_offset(&stmt.induc_from, stmt.special_cases_equal_tos.len())
324 .replace_with_numeric_result_if_can_be_calculated()
325 .0;
326 dom.push(
327 GreaterEqualFact::new(
328 obj_for_bound_param_in_scope(param_name.clone(), ParamObjType::Forall),
329 induc_plus_n,
330 stmt.line_file.clone(),
331 )
332 .into(),
333 );
334
335 let forall_fact_raw = ForallFact::new(
336 ParamDefWithType::new(param_def),
337 dom,
338 vec![EqualFact::new(
339 FnObj::new(
340 FnObjHead::Identifier(Identifier::new(stmt.name.clone())),
341 vec![vec![Box::new(obj_for_bound_param_in_scope(
342 param_name.clone(),
343 ParamObjType::Forall,
344 ))]],
345 )
346 .into(),
347 eq.clone(),
348 stmt.line_file.clone(),
349 )
350 .into()],
351 stmt.line_file.clone(),
352 )?;
353
354 let forall_fact = self
355 .inst_have_fn_forall_fact_for_store(forall_fact_raw)
356 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
357
358 let result = self
359 .verify_well_defined_and_store_and_infer_with_default_verify_state(
360 forall_fact.clone(),
361 )
362 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
363 Self::merge_store_infer_with_fallback_fact(&mut infer_result, result, &forall_fact);
364 }
365 HaveFnByInducLastCase::NestedCases(last_pairs) => {
366 for nested in last_pairs.iter() {
367 let param_name = stmt.param.clone();
368 let param_def = vec![ParamGroupWithParamType::new(
369 vec![param_name.clone()],
370 ParamType::Obj(StandardSet::Z.into()),
371 )];
372 let eq = nested.equal_to.clone();
373
374 let mut dom: Vec<Fact> = stmt.forall_fn_base_dom_exist_or_facts();
375
376 let induc_plus_n =
377 induc_obj_plus_offset(&stmt.induc_from, stmt.special_cases_equal_tos.len())
378 .replace_with_numeric_result_if_can_be_calculated()
379 .0;
380 dom.push(
381 GreaterEqualFact::new(
382 obj_for_bound_param_in_scope(param_name.clone(), ParamObjType::Forall),
383 induc_plus_n,
384 stmt.line_file.clone(),
385 )
386 .into(),
387 );
388
389 let c: AndChainAtomicFact = nested.case_fact.clone();
390 dom.push(c.into());
391
392 let forall_fact_raw = ForallFact::new(
393 ParamDefWithType::new(param_def),
394 dom,
395 vec![EqualFact::new(
396 FnObj::new(
397 FnObjHead::Identifier(Identifier::new(stmt.name.clone())),
398 vec![vec![Box::new(obj_for_bound_param_in_scope(
399 param_name.clone(),
400 ParamObjType::Forall,
401 ))]],
402 )
403 .into(),
404 eq.clone(),
405 stmt.line_file.clone(),
406 )
407 .into()],
408 stmt.line_file.clone(),
409 )?;
410
411 let forall_fact = self
412 .inst_have_fn_forall_fact_for_store(forall_fact_raw)
413 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
414
415 let result = self
416 .verify_well_defined_and_store_and_infer_with_default_verify_state(
417 forall_fact.clone(),
418 )
419 .map_err(|e| Self::have_fn_by_induc_err(stmt, e))?;
420 Self::merge_store_infer_with_fallback_fact(
421 &mut infer_result,
422 result,
423 &forall_fact,
424 );
425 }
426 }
427 }
428
429 Ok(infer_result)
430 }
431
432 pub fn exec_have_fn_by_induc_stmt(
433 &mut self,
434 stmt: &HaveFnByInducStmt,
435 ) -> Result<StmtResult, RuntimeError> {
436 self.exec_have_fn_by_induc(stmt)
437 }
438}