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