示例#1
0
def construct_and(proof_step, user_input: [str]) -> CodeForLean:
    """
    Split the target 'P AND Q' into two sub-goals.
    """
    target = proof_step.goal.target.math_type

    if not target.is_and(is_math_type=True):
        raise WrongUserInput(error=_("Target is not a conjunction 'P AND Q'"))

    left = target.children[0]
    right = target.children[1]
    if not user_input:
        # User choice
        choices = [(_("Left"), left.to_display()),
                   (_("Right"), right.to_display())]
        raise MissingParametersError(
            InputType.Choice,
            choices,
            title=_("Choose sub-goal"),
            output=_("Which property to prove first?"))
    else:
        if user_input[0] == 1:
            # Prove second property first
            if target.node == "PROP_∃":
                # In this case, first rw target as a conjunction
                code = CodeForLean.and_then_from_list(
                    ["rw exists_prop", "rw and.comm"])
            else:
                code = CodeForLean.from_string("rw and.comm")
            left, right = right, left
        else:
            code = CodeForLean.empty_code()
        code = code.and_then("split")
        code.add_success_msg(_('Target split'))
        code.add_conjunction(target, left, right)
    return code
示例#2
0
def apply_forall(proof_step, l: [MathObject]) -> CodeForLean:
    """
    Try to apply last selected property on the other ones.
    The last property should be a universal property
    (or equivalent to such after unfolding definitions)

    :param l: list of MathObjects of length ≥ 2
    :return:
    """
    # FIXME: return error msg if user try to apply "forall x:X, P(x)"
    #  to some object of wrong type (e.g. implication)
    #  For the moment "forall x, P->Q" works with "P->Q" and button forall

    goal = proof_step.goal
    universal_property = l[-1]  # The property to be applied
    unsolved_inequality_counter = 0
    # Variable_names will contain the list of variables and proofs of
    # inequalities that will be passed to universal_property
    variable_names = []
    code = CodeForLean.empty_code()
    for potential_var in l[:-1]:
        # TODO: replace by pattern matching
        # Check for "∀x>0" (and variations)
        inequality = inequality_from_pattern_matching(universal_property,
                                                      potential_var)
        variable_names.append(potential_var.info['name'])
        if inequality:
            math_types = [p.math_type for p in goal.context]
            if inequality in math_types:
                index = math_types.index(inequality)
                inequality_name = goal.context[index].display_name
                variable_names.append(inequality_name)
            else:
                inequality_name = get_new_hyp(proof_step)
                variable_names.append(inequality_name)
                unsolved_inequality_counter += 1
                # Add type indication to the variable in inequality
                math_type = inequality.children[1].math_type
                # Variable is not used explicitly, but this affects inequality:
                variable = inequality.children[0]
                variable = add_type_indication(variable, math_type)
                display_inequality = inequality.to_display(is_math_type=False,
                                                           format_='lean')
                # Code I: state corresponding inequality #
                code = code.and_then(f"have {inequality_name}: "
                                     f"{display_inequality}")
                code = code.and_then("rotate")

    # Code II: Apply universal_property #
    new_hypo_name = get_new_hyp(proof_step)
    code = code.and_then(
        have_new_property(universal_property, variable_names, new_hypo_name))

    # Code III: try to solve inequalities #     e.g.:
    #   iterate 2 { solve1 {try {norm_num at *}, try {compute_n 10}} <|>
    #               rotate},   rotate,
    more_code = CodeForLean.empty_code()
    if unsolved_inequality_counter:
        code = code.and_then("rotate")  # back to first inequality
        more_code1 = CodeForLean.from_string("norm_num at *")
        more_code1 = more_code1.try_()
        more_code2 = CodeForLean.from_string("compute_n 1")
        more_code2 = more_code2.try_()
        # Try to solve1 inequality by norm_num, maybe followed by compute:
        more_code = more_code1.and_then(more_code2)
        more_code = more_code.single_combinator("solve1")
        # If it fails, rotate to next inequality
        more_code = more_code.or_else("rotate")
        # Do this for all inequalities
        #   more_code = more_code.single_combinator(f"iterate
        #   {unsolved_inequality_counter}") --> replaced by explicit iteration
        code_list = [more_code] * unsolved_inequality_counter
        more_code = CodeForLean.and_then_from_list(code_list)
        # Finally come back to first inequality
        more_code = more_code.and_then("rotate")

    code.add_success_msg(
        _("Property {} added to the context").format(new_hypo_name))
    return code.and_then(more_code)