def action_negate(proof_step, selected_objects: [MathObject], target_selected: bool = True) -> CodeForLean: """ Translate into string of lean code corresponding to the action If no hypothesis has been previously selected: transform the target in an equivalent one with its negations 'pushed'. If a hypothesis has been previously selected: do the same to the hypothesis. """ test_selection(selected_objects, target_selected) goal = proof_step.goal if len(selected_objects) == 0: if not goal.target.is_not(): raise WrongUserInput(error=_("Target is not a negation 'NOT P'")) code = CodeForLean.from_string('push_neg') code.add_success_msg(_("Negation pushed on target")) elif len(selected_objects) == 1: if not selected_objects[0].is_not(): error = _("Selected property is not a negation 'NOT P'") raise WrongUserInput(error) selected_hypo = selected_objects[0].info["name"] code = CodeForLean.from_string(f'push_neg at {selected_hypo}') code.add_success_msg( _(f"Negation pushed on property " f"{selected_hypo}")) else: raise WrongUserInput(error=_('Only one property at a time')) return code
def action_or(proof_step, selected_objects: [MathObject], user_input=None, target_selected: bool = True) -> CodeForLean: """ If the target is of the form P OR Q: transform the target in P (or Q) according to the user's choice. If a hypothesis of the form P OR Q has been previously selected: transform the current goal into two subgoals, one with P as a hypothesis, and another with Q as a hypothesis. """ test_selection(selected_objects, target_selected) goal = proof_step.goal if len(selected_objects) == 0: if not goal.target.is_or(): raise WrongUserInput( error=_("Target is not a disjunction 'P OR Q'")) else: return construct_or(proof_step, user_input) elif len(selected_objects) == 1: if selected_objects[0].is_or(): return apply_or(proof_step, selected_objects, user_input) else: return construct_or_on_hyp(proof_step, selected_objects, user_input) elif len(selected_objects) == 2: return construct_or_on_hyp(proof_step, selected_objects, user_input) else: # More than 2 selected objects raise WrongUserInput(error=_("Does not apply to more than two " "properties"))
def action_and(proof_step, selected_objects: [MathObject], user_input: [str] = None, target_selected: bool = True) -> CodeForLean: """ Translate into string of lean code corresponding to the action If the target is of the form P AND Q: transform the current goal into two subgoals, P, then Q. If a hypothesis of the form P AND Q has been previously selected: creates two new hypothesis P, and Q. If two hypothesis P, then Q, have been previously selected: add the new hypothesis P AND Q to the properties. """ test_selection(selected_objects, target_selected) goal = proof_step.goal if len(selected_objects) == 0: return construct_and(proof_step, user_input) if len(selected_objects) == 1: if not selected_objects[0].is_and(): raise WrongUserInput(error=_("Selected property is not " "a conjunction 'P AND Q'")) else: return apply_and(proof_step, selected_objects) if len(selected_objects) == 2: if not (selected_objects[0].math_type.is_prop and selected_objects[1].math_type.is_prop): raise WrongUserInput(error=_("Selected items are not properties")) else: return construct_and_hyp(proof_step, selected_objects) raise WrongUserInput(error=_("Does not apply to more than two properties"))
def action_forall(proof_step, selected_objects: [MathObject], user_input: [str] = [], target_selected: bool = True) -> CodeForLean: """ (1) If no selection and target is of the form ∀ x, P(x): introduce x and transform the target into P(x) (2) If a single universal property is selected, ask user for an object to which the property will be applied (3) If 2 or more items are selected, one of which is a universal property, try to apply it to the other selected items """ test_selection(selected_objects, target_selected) goal = proof_step.goal if len(selected_objects) == 0: if not goal.target.is_for_all(): error = _("target is not a universal property '∀x, P(x)'") raise WrongUserInput(error) else: return construct_forall(proof_step) elif len(selected_objects) == 1: # Ask user for item if not selected_objects[0].is_for_all(): error = _("selected property is not a universal property '∀x, " "P(x)'") raise WrongUserInput(error) elif not user_input: raise MissingParametersError(InputType.Text, title=_("Apply a universal property"), output=_("Enter element on which you " "want to apply:")) else: item = user_input[0] item = add_type_indication(item) # e.g. (0:ℝ) if item[0] != '(': item = '(' + item + ')' potential_var = MathObject(node="LOCAL_CONSTANT", info={'name': item}, children=[], math_type=None) selected_objects.insert(0, potential_var) # Now len(l) == 2 # From now on len(l) ≥ 2 # Search for a universal property among l, beginning with last item selected_objects.reverse() for item in selected_objects: if item.is_for_all(): # Put item on last position selected_objects.remove(item) selected_objects.reverse() selected_objects.append(item) return apply_forall(proof_step, selected_objects) raise WrongUserInput(error=_("no universal property among selected"))
def action_definition(proof_step, selected_objects: [MathObject], definition, target_selected: bool = True ): """ Apply definition to rewrite selected object or target. """ test_selection(selected_objects, target_selected) codes = rw_using_statement(proof_step.goal, selected_objects, definition) codes.add_error_msg(_("unable to apply definition")) return codes
def action_exists(proof_step, selected_objects: [MathObject], user_input: [str] = None, target_selected: bool = True) -> CodeForLean: """ Three cases: (1) If target is of form ∃ x, P(x): - if no selection, ask the user to enter a witness x and transform the target into P(x). - if some selection, use it as a witness for existence. (2) If a hypothesis of form ∃ x, P(x) has been previously selected: introduce a new x and add P(x) to the properties. (3) If some 'x' and a property P(x) have been selected: get property '∃ x, P(x)' """ test_selection(selected_objects, target_selected) goal = proof_step.goal if len(selected_objects) == 0: if not goal.target.is_exists(): error = _("target is not existential property '∃x, P(x)'") raise WrongUserInput(error) else: return construct_exists(proof_step, user_input) elif len(selected_objects) == 1 and not user_input: selected_hypo = selected_objects[0] if selected_hypo.math_type.is_prop(): # Try to apply property "exists x, P(x)" to get a new MathObject x if not selected_hypo.is_exists(): error = _("selection is not existential property '∃x, P(x)'") raise WrongUserInput(error) else: return apply_exists(proof_step, selected_objects) else: # h_selected is not a property : get an existence property if not goal.target.is_exists(): error = _("target is not existential property '∃x, P(x)'") raise WrongUserInput(error) else: object_name = selected_objects[0].info["name"] return construct_exists(proof_step, [object_name]) elif len(selected_objects) == 2: return construct_exists_on_hyp(proof_step, selected_objects) raise WrongUserInput(error=_("does not apply to more than two properties"))
def action_iff(proof_step, selected_objects: [MathObject], user_input: [str] = [], target_selected: bool = True) -> CodeForLean: """ Three cases: (1) No selected property: If the target is of the form P ⇔ Q: introduce two subgoals, P⇒Q, and Q⇒P. If target is of the form (P → Q) ∧ (Q → P): replace by P ↔ Q (2) 1 selected property, which is an iff P ⇔ Q: split it into two implications P⇒Q, and Q⇒P. (3) 2 properties: try to obtain P ⇔ Q. """ test_selection(selected_objects, target_selected) goal = proof_step.goal if len(selected_objects) == 0: if goal.target.math_type.node != "PROP_IFF": code = destruct_iff(proof_step) if code: return code else: raise WrongUserInput( error=_("target is not an iff property 'P ⇔ Q'")) else: return construct_iff(proof_step, user_input) if len(selected_objects) == 1: if selected_objects[0].math_type.node != "PROP_IFF": error = _("selected property is not an iff property 'P ⇔ Q'") raise WrongUserInput(error) else: return destruct_iff_on_hyp(proof_step, selected_objects) if len(selected_objects) == 2: if not (selected_objects[0].math_type.is_prop() and selected_objects[1].math_type.is_prop()): error = _("selected items should both be implications") raise WrongUserInput(error) else: return construct_iff_on_hyp(proof_step, selected_objects) raise WrongUserInput(error=_("does not apply to more than two properties"))
def action_implicate(proof_step, selected_objects: [MathObject], target_selected: bool = True) -> CodeForLean: """ Three cases: (1) No property selected: If the target is of the form P ⇒ Q: introduce the hypothesis P in the properties and transform the target into Q. (2) A single selected property, of the form P ⇒ Q: If the target was Q, it is replaced by P (3) Exactly two selected property, on of which is an implication P ⇒ Q and the other is P: Add Q to the context """ test_selection(selected_objects, target_selected) goal = proof_step.goal if len(selected_objects) == 0: if not goal.target.is_implication(): raise WrongUserInput( error=_("Target is not an implication 'P ⇒ Q'")) else: return construct_implicate(proof_step) if len(selected_objects) == 1: if not selected_objects[0].can_be_used_for_implication(): raise WrongUserInput( error=_("Selected property is not an implication 'P ⇒ Q'")) else: return apply_implicate(proof_step, selected_objects) elif len(selected_objects) == 2: if not selected_objects[-1].can_be_used_for_implication(): if not selected_objects[0].can_be_used_for_implication(): raise WrongUserInput(error=_( "Selected properties are not implications 'P ⇒ Q'")) else: # l[0] is an implication but not l[1]: permute selected_objects.reverse() return apply_implicate_to_hyp(proof_step, selected_objects) # TODO: treat the case of more properties, including the possibility of # P, Q and 'P and Q ⇒ R' raise WrongUserInput(error=_("Does not apply to more than two properties"))