Skip to main content

litex/verify/
verify_restrict_by_def.rs

1// restrict_fn_in proof pipeline:
2// step1: forall on RHS params, verify f(x, ...) is well-defined.
3// step2: get known fn-set info of f from env.
4// step2_1: if known return-set equals RHS return-set, accept immediately.
5// step2_2: otherwise prove forall RHS params: f(x, ...) is in RHS return-set.
6
7// Example:
8// have f fn(x R, y Q: x < y) Z
9// restrict_fn_in(f, fn(a Q, b Q: x < y, x < 0) Z)
10// 1. prove forall a Q, b Q: x < y: f(a, b) is well-defined.
11// 2. prove restriction keeps outputs in Z.
12// 2.1 if known return_set of f is already Z, return success directly.
13// 2.2 otherwise build and verify:
14//     forall a Q, b Q: x < y, x < 0: f(a, b) $in Z
15
16use crate::prelude::*;
17struct RestrictProofFlow {
18    // The whole restrict_fn_in(...) fact to be proved.
19    restrict_fact: RestrictFact,
20    // The RHS function set in restrict_fn_in, e.g. fn(a Q, b Q: x < y, x < 0) Z.
21    rhs_fn_set: FnSet,
22    // Known function-set body of f from env, e.g. fn(x R, y Q: x < y) Z.
23    known_fn_body: FnSetBody,
24    // Forall binders for step 1/2.2, e.g. a Q, b Q.
25    forall_params: ParamDefWithType,
26    // Forall domain facts for step 1/2.2, e.g. x < y, x < 0.
27    forall_dom_facts: Vec<Fact>,
28    // Applied function object under forall vars, e.g. f(a, b).
29    applied_fn_obj: Obj,
30}
31
32impl Runtime {
33    pub fn verify_restrict_fact_using_its_definition(
34        &mut self,
35        restrict_fact: &RestrictFact,
36        verify_state: &VerifyState,
37    ) -> Result<Option<StmtResult>, RuntimeError> {
38        self.restrict_step_0_verify_input_objects_well_defined(restrict_fact, verify_state)?;
39
40        let flow = match self.restrict_step_2_build_flow_from_env(restrict_fact)? {
41            Some(v) => v,
42            None => return Ok(None),
43        };
44
45        self.restrict_step_1_verify_forall_application_well_defined(&flow, verify_state)?;
46
47        if let Some(success) = self.restrict_step_2_1_try_return_set_shortcut(&flow) {
48            return Ok(Some(success));
49        }
50
51        self.restrict_step_2_2_prove_forall_membership_in_rhs_return_set(flow, verify_state)
52    }
53
54    fn restrict_wrap_verify_runtime_error(
55        restrict_fact: &RestrictFact,
56        cause: RuntimeError,
57    ) -> RuntimeError {
58        RuntimeError::from(VerifyRuntimeError(RuntimeErrorStruct::new(
59            Some(Fact::from(restrict_fact.clone()).into_stmt()),
60            String::new(),
61            restrict_fact.line_file.clone(),
62            Some(cause),
63            vec![],
64        )))
65    }
66
67    fn restrict_step_0_verify_input_objects_well_defined(
68        &mut self,
69        restrict_fact: &RestrictFact,
70        verify_state: &VerifyState,
71    ) -> Result<(), RuntimeError> {
72        self.verify_obj_well_defined_and_store_cache(&restrict_fact.obj, verify_state)
73            .map_err(|e| Self::restrict_wrap_verify_runtime_error(restrict_fact, e))?;
74        self.verify_obj_well_defined_and_store_cache(
75            &restrict_fact.obj_can_restrict_to_fn_set,
76            verify_state,
77        )
78        .map_err(|e| Self::restrict_wrap_verify_runtime_error(restrict_fact, e))?;
79        Ok(())
80    }
81
82    fn restrict_step_2_build_flow_from_env(
83        &mut self,
84        restrict_fact: &RestrictFact,
85    ) -> Result<Option<RestrictProofFlow>, RuntimeError> {
86        let rhs_fn_set = match &restrict_fact.obj_can_restrict_to_fn_set {
87            Obj::FnSet(v) => v.clone(),
88            _ => return Ok(None),
89        };
90
91        let known_fn_body =
92            self.restrict_step_2_get_known_fn_set_info(&restrict_fact.obj, restrict_fact)?;
93
94        let rhs_flat_param_names = self.restrict_collect_flat_param_names(&rhs_fn_set.body);
95        let known_flat_param_names = self.restrict_collect_flat_param_names(&known_fn_body);
96        if rhs_flat_param_names.len() != known_flat_param_names.len() {
97            return Ok(None);
98        }
99
100        let forall_params = self.restrict_build_forall_params_from_rhs(&rhs_fn_set.body);
101        let forall_dom_facts = self.restrict_build_forall_dom_facts_from_rhs(&rhs_fn_set.body);
102
103        let fn_head = match FnObjHead::given_an_atom_return_a_fn_obj_head(restrict_fact.obj.clone())
104        {
105            Some(v) => v,
106            None => return Ok(None),
107        };
108        let applied_fn_obj: Obj = FnObj::new(
109            fn_head,
110            self.restrict_build_full_application_arg_groups(&known_fn_body, &rhs_flat_param_names),
111        )
112        .into();
113
114        Ok(Some(RestrictProofFlow {
115            restrict_fact: restrict_fact.clone(),
116            rhs_fn_set,
117            known_fn_body,
118            forall_params,
119            forall_dom_facts,
120            applied_fn_obj,
121        }))
122    }
123
124    fn restrict_step_2_get_known_fn_set_info(
125        &self,
126        function: &Obj,
127        restrict_fact: &RestrictFact,
128    ) -> Result<FnSetBody, RuntimeError> {
129        match self.get_cloned_object_in_fn_set(function) {
130            Some(v) => Ok(v),
131            None => match self.get_cloned_object_in_fn_set_or_restrict(function) {
132                Some(v) => Ok(v),
133                None => Err(VerifyRuntimeError(RuntimeErrorStruct::new(
134                    Some(Fact::from(restrict_fact.clone()).into_stmt()),
135                    String::new(),
136                    restrict_fact.line_file.clone(),
137                    Some(
138                        WellDefinedRuntimeError(RuntimeErrorStruct::new(
139                            None,
140                            format!(
141                                "function `{}` belongs to what function set is unknown",
142                                function.to_string()
143                            ),
144                            default_line_file(),
145                            None,
146                            vec![],
147                        ))
148                        .into(),
149                    ),
150                    vec![],
151                ))
152                .into()),
153            },
154        }
155    }
156
157    fn restrict_step_1_verify_forall_application_well_defined(
158        &mut self,
159        flow: &RestrictProofFlow,
160        verify_state: &VerifyState,
161    ) -> Result<(), RuntimeError> {
162        self.restrict_step_1_verify_by_local_param_def(flow, verify_state)?;
163        self.restrict_step_1_verify_under_rhs_dom_facts(flow, verify_state)?;
164        Ok(())
165    }
166
167    fn restrict_step_1_verify_by_local_param_def(
168        &mut self,
169        flow: &RestrictProofFlow,
170        _verify_state: &VerifyState,
171    ) -> Result<(), RuntimeError> {
172        self.verify_obj_well_defined_with_its_local_def(
173            flow.rhs_fn_set.body.params_def_with_set.clone(),
174            ParamObjType::Forall,
175            flow.applied_fn_obj.clone(),
176        )
177        .map_err(|e| Self::restrict_wrap_verify_runtime_error(&flow.restrict_fact, e))
178    }
179
180    fn restrict_step_1_verify_under_rhs_dom_facts(
181        &mut self,
182        flow: &RestrictProofFlow,
183        verify_state: &VerifyState,
184    ) -> Result<(), RuntimeError> {
185        let stub = ForallFact::new(
186            flow.forall_params.clone(),
187            flow.forall_dom_facts.clone(),
188            Vec::new(),
189            flow.restrict_fact.line_file.clone(),
190        )?;
191        self.run_in_local_env(|rt| {
192            rt.forall_assume_params_and_dom_in_current_env(&stub, verify_state)?;
193            rt.verify_obj_well_defined_and_store_cache(&flow.applied_fn_obj, verify_state)
194        })
195        .map_err(|e| Self::restrict_wrap_verify_runtime_error(&flow.restrict_fact, e))
196    }
197
198    fn restrict_step_2_1_try_return_set_shortcut(
199        &self,
200        flow: &RestrictProofFlow,
201    ) -> Option<StmtResult> {
202        if crate::verify::verify_equality_by_builtin_rules::objs_equal_by_display_string(
203            flow.known_fn_body.ret_set.as_ref(),
204            flow.rhs_fn_set.body.ret_set.as_ref(),
205        ) {
206            return Some(
207                (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
208                    flow.restrict_fact.clone().into(),
209                    "restrict_fn_in: well-defined on narrowed domain; known fn_set already has same return_set"
210                        .to_string(),
211                    Vec::new(),
212                ))
213                .into(),
214            );
215        }
216        None
217    }
218
219    fn restrict_step_2_2_prove_forall_membership_in_rhs_return_set(
220        &mut self,
221        flow: RestrictProofFlow,
222        verify_state: &VerifyState,
223    ) -> Result<Option<StmtResult>, RuntimeError> {
224        let then_facts = vec![InFact::new(
225            flow.applied_fn_obj.clone(),
226            (*flow.rhs_fn_set.body.ret_set).clone(),
227            flow.restrict_fact.line_file.clone(),
228        )
229        .into()];
230
231        let forall = ForallFact::new(
232            flow.forall_params,
233            flow.forall_dom_facts,
234            then_facts,
235            flow.restrict_fact.line_file.clone(),
236        )?;
237
238        let forall_result = self.verify_forall_fact(&forall, verify_state)?;
239        if !forall_result.is_true() {
240            return Ok(None);
241        }
242        Ok(Some(
243            (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
244                flow.restrict_fact.clone().into(),
245                "restrict_fn_in: forall on narrowed domain; outputs in stated return set"
246                    .to_string(),
247                Vec::new(),
248            ))
249            .into(),
250        ))
251    }
252
253    fn restrict_collect_flat_param_names(&self, body: &FnSetBody) -> Vec<String> {
254        let mut out: Vec<String> = Vec::new();
255        for g in body.params_def_with_set.iter() {
256            for name in g.params.iter() {
257                out.push(name.clone());
258            }
259        }
260        out
261    }
262
263    fn restrict_build_forall_params_from_rhs(&self, rhs_body: &FnSetBody) -> ParamDefWithType {
264        let mut groups: Vec<ParamGroupWithParamType> = Vec::new();
265        for param_def_with_set in &rhs_body.params_def_with_set {
266            groups.push(ParamGroupWithParamType::new(
267                param_def_with_set.params.clone(),
268                ParamType::Obj(param_def_with_set.set.clone()),
269            ));
270        }
271        ParamDefWithType::new(groups)
272    }
273
274    fn restrict_build_forall_dom_facts_from_rhs(&self, rhs_body: &FnSetBody) -> Vec<Fact> {
275        let mut out: Vec<Fact> = Vec::new();
276        for dom_fact in rhs_body.dom_facts.iter() {
277            let chain: OrAndChainAtomicFact = dom_fact.clone();
278            out.push(chain.into());
279        }
280        out
281    }
282
283    fn restrict_build_full_application_arg_groups(
284        &self,
285        known_fn_body: &FnSetBody,
286        rhs_flat_param_names: &[String],
287    ) -> Vec<Vec<Box<Obj>>> {
288        let mut all_args: Vec<Box<Obj>> = Vec::new();
289        let mut index: usize = 0;
290        for param_group in known_fn_body.params_def_with_set.iter() {
291            for _ in param_group.params.iter() {
292                let rhs_param_name = rhs_flat_param_names[index].clone();
293                all_args.push(Box::new(obj_for_bound_param_in_scope(
294                    rhs_param_name,
295                    ParamObjType::Forall,
296                )));
297                index += 1;
298            }
299        }
300        vec![all_args]
301    }
302}