示例#1
0
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
示例#2
0
def construct_or(proof_step, user_input: [str]) -> CodeForLean:
    """
    Assuming target is a disjunction 'P OR Q', choose to prove either P or Q.
    """
    target = proof_step.goal.target

    left = target.math_type.children[0].to_display()
    right = target.math_type.children[1].to_display()
    choices = [(_("Left"), left), (_("Right"), right)]

    if not user_input:
        raise MissingParametersError(InputType.Choice,
                                     choices,
                                     title=_("Choose new goal"),
                                     output=_("Which property will you "
                                              "prove?"))
    code = None
    if len(user_input) == 1:
        i = user_input[0]
        if i == 0:
            code = CodeForLean.from_string("left")
            code.add_success_msg(_("Target replaced by the left alternative"))
        else:
            code = CodeForLean.from_string("right")
            code.add_success_msg(_("Target replaced by the right alternative"))

    return code
示例#3
0
def action_compute(proof_step, selected_objects, target_selected: bool = True):
    """
    If the target is an equality, an inequality (or 'False'), then send
    tactics trying to prove the goal by (mainly linearly) computing.
    """

    goal = proof_step.goal

    target = goal.target
    if not (target.is_equality() or target.is_inequality()
            or target.is_false()):
        error = _("target is not an equality, an inequality, "
                  "nor a contradiction")
        raise WrongUserInput(error)
    # try_before = "try {apply div_pos}, " \
    #            + "try { all_goals {norm_num at *}}" \
    #             + ", "
    # simplify_1 = "simp only " \
    #             + "[*, ne.symm, ne.def, not_false_iff, lt_of_le_of_ne]"
    # possible_code = [try_before + "linarith",
    #                 try_before + simplify_1]
    # "finish" "norm_num *"
    # if user_config.getboolean('use_library_search_for_computations'):
    #     possible_code.append('library_search')
    code1 = CodeForLean.from_string("norm_num at *").solve1()
    code2 = CodeForLean.from_string("compute_n 10")
    code3 = CodeForLean.from_string("norm_num at *").try_().and_then(code2)
    possible_code = code1.or_else(code3)
    #possible_code = [solve1_wrap("norm_num at *"),
    #                 solve1_wrap("try {norm_num at *}, compute_n 10")]
    return possible_code
示例#4
0
def action_assumption(proof_step,
                      selected_objects: [MathObject],
                      target_selected: bool = True) -> CodeForLean:
    """
    Translate into string of lean code corresponding to the action.
    """

    goal = proof_step.goal

    # (1) First trials
    target = goal.target
    improved_assumption = solve_target(target)
    codes = [improved_assumption]

    # (2) Use user selection
    if len(selected_objects) == 1:
        apply_user = CodeForLean.from_string(
            f'apply {selected_objects[0].info["name"]}')
        codes.append(apply_user.solve1())

    # (3) Conjunctions: try to split hypotheses once
    # TODO: recursive splitting in hypo
    # And then retry many things (in improved_assumption_2).
    split_conj = split_conjunctions_in_context(proof_step)

    improved_assumption_2 = solve_target(target)
    # Split target
    if target.is_and():
        # TODO: recursive splitting in target, and_then for each subgoal
        #  apply improved_assumption
        split_code = CodeForLean.from_string('split, assumption, assumption')
        improved_assumption_2 = improved_assumption_2.or_else(split_code)

    # Try norm_num
    if (goal.target.is_equality() or goal.target.is_inequality()
            or goal.target.is_false()):
        # Do not remove above test, since norm_num may solve some
        # not-so-trivial goal, e.g. implications
        norm_num_code = CodeForLean.from_string('norm_num at *').solve1()
        improved_assumption_2 = improved_assumption_2.or_else(norm_num_code)

    # Try specific properties
    more_assumptions = search_specific_prop(proof_step)
    if not more_assumptions.is_empty():
        improved_assumption_2 = improved_assumption_2.or_else(more_assumptions)
    more_code = split_conj.and_then(improved_assumption_2)
    codes.append(more_code)
    code = CodeForLean.or_else_from_list(codes)
    code = code.solve1()
    code.add_error_msg(_("I don't know how to conclude"))
    return code
示例#5
0
def apply_implicate(proof_step, selected_object: [MathObject]) -> CodeForLean:
    """
    Here selected_object contains a single property which is an implication
    P ⇒ Q; if the target is Q then it will be replaced by P.
    """
    selected_hypo = selected_object[0].info["name"]
    code = CodeForLean.from_string(f'apply {selected_hypo}')
    code.add_success_msg(
        _("Target modified using implication {}").format(selected_hypo))
    return code
示例#6
0
def method_absurdum(proof_step, selected_objects: [MathObject]) -> CodeForLean:
    """
    If no selection, engage in a proof by contradiction.
    """
    if len(selected_objects) == 0:
        new_hypo = get_new_hyp(proof_step)
        code = CodeForLean.from_string(f'by_contradiction {new_hypo}')
        code.add_success_msg(_("Negation of target added to the context"))
        return code
    else:
        error = _('Proof by contradiction only applies to target')
    raise WrongUserInput(error)
示例#7
0
def construct_implicate(proof_step) -> CodeForLean:
    """
    Here the target is assumed to be an implication P ⇒ Q, P is added to the
    context, and the target becomes Q.
    """
    if not proof_step.goal.target.is_implication():
        raise WrongUserInput(error=_("Target is not an implication 'P ⇒ Q'"))
    else:
        new_hypo_name = get_new_hyp(proof_step)
        code = CodeForLean.from_string(f'intro {new_hypo_name}')
        code.add_success_msg(
            _("Property {} added to the context").format(new_hypo_name))
        return code
示例#8
0
def construct_forall(proof_step) -> CodeForLean:
    """
    Here goal.target is assumed to be a universal property "∀ x:X, ...",
    and variable x is introduced.
    """

    goal = proof_step.goal
    math_object = goal.target.math_type
    math_type = math_object.children[0]
    variable = math_object.children[1]
    body = math_object.children[2]
    hint = variable.display_name  # not optimal
    if math_type.node == "PRODUCT":
        [math_type_1, math_type_2] = math_type.children
        x = give_global_name(proof_step=proof_step, math_type=math_type_1)
        y = give_global_name(proof_step=proof_step, math_type=math_type_2)
        possible_codes = CodeForLean.from_string(f'rintro ⟨ {x}, {y} ⟩')
        name = f"({x},{y})"
    else:
        x = give_global_name(proof_step=proof_step,
                             math_type=math_type,
                             hints=[hint])
        possible_codes = CodeForLean.from_string(f'intro {x}')
        name = f"{x}"
    possible_codes.add_success_msg(
        _("Object {} added to the context").format(name))

    if body.is_implication(is_math_type=True):
        # If math_object has the form
        # ∀ x:X, (x R ... ==> ...)
        # where R is some inequality relation
        # then introduce the inequality on top of x
        premise = body.children[0]  # children (2,0)
        if premise.is_inequality(is_math_type=True):
            h = get_new_hyp(proof_step)
            # Add and_then intro h
            possible_codes = possible_codes.and_then(f'intro {h}')

    return possible_codes
示例#9
0
def apply_and(proof_step, selected_objects) -> CodeForLean:
    """
    Destruct a property 'P and Q'.
    Here selected_objects is assumed to contain exactly one conjunction
    property.
    """

    selected_hypo = selected_objects[0].info["name"]
    h1 = get_new_hyp(proof_step)
    h2 = get_new_hyp(proof_step)
    code = CodeForLean.from_string(f'cases {selected_hypo} with {h1} {h2}')
    code.add_success_msg(
        _("Split property {} into {} and {}").format(selected_hypo, h1, h2))
    return code
示例#10
0
def construct_and_hyp(proof_step, selected_objects: [MathObject]) \
                      -> CodeForLean:
    """
    Construct 'P AND Q' from properties P and Q.
    Here selected_objects is assumed to contain exactly two properties.
    """

    h1 = selected_objects[0].info["name"]
    h2 = selected_objects[1].info["name"]
    new_hypo_name = get_new_hyp(proof_step)
    code = f'have {new_hypo_name} := and.intro {h1} {h2}'
    code = CodeForLean.from_string(code)
    code.add_success_msg(
        _("Conjunction {} added to the context").format(new_hypo_name))
    return code
示例#11
0
def construct_iff_on_hyp(proof_step,
                         selected_objects: [MathObject]) -> CodeForLean:
    """
    Construct property 'P iff Q' from both implications.
    len(selected_objects) should be 2.
    """

    new_hypo_name = get_new_hyp(proof_step)
    h1 = selected_objects[0].info["name"]
    h2 = selected_objects[1].info["name"]
    code_string = f'have {new_hypo_name} := iff.intro {h1} {h2}'
    code = CodeForLean.from_string(code_string)
    code.add_success_msg(
        _("Logical equivalence {} added to the context").format(new_hypo_name))
    return code
示例#12
0
def construct_exists(proof_step, user_input: [str]) -> CodeForLean:
    """
    Assuming the target is an existential property '∃ x, P(x)', prove it by
    providing a witness x and proving P(x).
    """

    if not user_input:
        raise MissingParametersError(
            InputType.Text,
            title=_("Exist"),
            output=_("Enter element you want to use:"))
    x = user_input[0]
    code = CodeForLean.from_string(f'use {x}, dsimp')
    code = code.or_else(f'use {x}')
    code.add_success_msg(_("now prove {} suits our needs").format(x))
    return code
示例#13
0
def destruct_iff(proof_step) -> CodeForLean:
    """
    Check if target is a conjunction of two implications (but not if these
    implications are logical inverses). If so, return code that builds the
    equivalent iff statement. If not, return None.
    """

    goal = proof_step.goal
    code = None
    target = goal.target
    if target.is_and():
        left = target.math_type.children[0]
        right = target.math_type.children[1]
        if left.is_implication(is_math_type=True) \
                and right.is_implication(is_math_type=True):
            code = CodeForLean.from_string("apply iff_def.mp")
            code.add_success_msg(_("target replaced by iff property"))
    return code
示例#14
0
def search_specific_prop(proof_step):
    """Search context for some specific properties to conclude the proof."""

    goal = proof_step.goal

    more_code = CodeForLean.empty_code()
    for prop in goal.context:
        math_type = prop.math_type
        # Conclude from "x in empty set"
        if (math_type.node == "PROP_BELONGS"
                and math_type.children[1].node == "SET_EMPTY"):
            hypo = prop.info['name']
            if goal.target.node != "PROP_FALSE":
                more_code = CodeForLean.from_string("exfalso")
            else:
                more_code = CodeForLean.empty_code()
            more_code = more_code.and_then(f"exact set.not_mem_empty _ {hypo}")

    return more_code
示例#15
0
def method_contrapose(proof_step,
                      selected_objects: [MathObject]) -> CodeForLean:
    """
    If target is an implication, turn it to its contrapose.
    """

    goal = proof_step.goal

    if len(selected_objects) == 0:
        if goal.target.math_type.node == "PROP_IMPLIES":
            code = CodeForLean.from_string("contrapose")
            code.add_success_msg(_("Target replaced by contrapositive"))
            return code
        else:
            error = _('Proof by contraposition only applies when target is '
                      'an implication')
    else:
        error = _('Proof by contraposition only applies to target')
    raise WrongUserInput(error)
示例#16
0
def introduce_fun(proof_step, selected_objects: [MathObject]) -> CodeForLean:
    """
    If a hypothesis of form ∀ a ∈ A, ∃ b ∈ B, P(a,b) has been previously
    selected: use the axiom of choice to introduce a new function f : A → B
    and add ∀ a ∈ A, P(a, f(a)) to the properties.
    """

    goal = proof_step.goal

    error = _('select a property "∀ x, ∃ y, P(x,y)" to get a function')
    success = _("function {} and property {} added to the context")
    if len(selected_objects) == 1:
        h = selected_objects[0].info["name"]
        # Finding expected math_type for the new function
        universal_property = selected_objects[0]
        if universal_property.is_for_all():
            source_type = universal_property.math_type.children[0]
            exist_property = universal_property.math_type.children[2]
            if exist_property.is_exists(is_math_type=True):
                target_type = exist_property.children[0]
                math_type = MathObject(node="FUNCTION",
                                       info={},
                                       children=[source_type, target_type],
                                       math_type=NO_MATH_TYPE)

                hf = get_new_hyp(proof_step)
                f = give_global_name(math_type=math_type,
                                     proof_step=proof_step)
                code = CodeForLean.from_string(f'cases '
                                               f'classical.axiom_of_choice '
                                               f'{h} with {f} {hf}, '
                                               f'dsimp at {hf}, '
                                               f'dsimp at {f}')
                code.add_error_msg(error)
                success = success.format(f, hf)
                code.add_success_msg(success)
                return code
    raise WrongUserInput(error)
示例#17
0
def construct_iff(proof_step, user_input: [str]) -> CodeForLean:
    """
    Assuming target is an iff, split into two implications.
    """

    target = proof_step.goal.target.math_type
    code = CodeForLean.empty_code()

    left = target.children[0]
    right = target.children[1]
    if not user_input:
        choices = [("⇒", f'({left.to_display()}) ⇒ ({right.to_display()})'),
                   ("⇐", f'({right.to_display()}) ⇒ ({left.to_display()})')]
        raise MissingParametersError(
            InputType.Choice,
            choices,
            title=_("Choose sub-goal"),
            output=_("Which implication to prove first?"))

    elif len(user_input) == 1:
        if user_input[0] == 1:
            code = CodeForLean.from_string("rw iff.comm")
            left, right = right, left
        code = code.and_then("split")
    else:
        raise WrongUserInput(error=_("Undocumented error"))
    code.add_success_msg(_("Iff split in two implications"))
    impl1 = MathObject(info={},
                       node="PROP_IMPLIES",
                       children=[left, right],
                       math_type="PROP")
    impl2 = MathObject(info={},
                       node="PROP_IMPLIES",
                       children=[right, left],
                       math_type="PROP")
    code.add_conjunction(target, impl1, impl2)
    return code
示例#18
0
def apply_or(proof_step, selected_objects: [MathObject],
             user_input: [str]) -> CodeForLean:
    """
    Assuming selected_objects is one disjunction 'P OR Q',
    engage in a proof by cases.
    """

    # if not selected_objects[0].is_or():
    #     raise WrongUserInput(error=_("Selected property is not "
    #                                  "a disjunction 'P OR Q'"))

    selected_hypo = selected_objects[0]
    code = CodeForLean.empty_code()

    left = selected_hypo.math_type.children[0]
    right = selected_hypo.math_type.children[1]
    if not user_input:
        choices = [(_("Left"), left.to_display()),
                   (_("Right"), right.to_display())]
        raise MissingParametersError(InputType.Choice,
                                     choices=choices,
                                     title=_("Choose case"),
                                     output=_("Which case to assume first?"))
    else:  # len(user_input) == 1
        if user_input[0] == 1:
            # If user wants the second property first, then first permute
            code = f'rw or.comm at {selected_hypo.info["name"]}'
            code = CodeForLean.from_string(code)
            left, right = right, left

    h1 = get_new_hyp(proof_step)
    h2 = get_new_hyp(proof_step)
    # Destruct the disjunction
    code = code.and_then(f'cases {selected_hypo.info["name"]} with {h1} {h2}')
    code.add_success_msg(_("Proof by cases"))
    code.add_disjunction(selected_hypo, left, right)
    return code
示例#19
0
def method_cbr(proof_step,
               selected_objects: [MathObject],
               user_input: [str] = []) -> CodeForLean:
    """
    Engage in a proof by cases.
    - If selection is empty, then ask the user to choose a property
    - If a disjunction is selected, use this disjunction for the proof by cases
    _ If anything else is selected try to discuss on this property
    (useful only in propositional calculus?)
    In any case, ask the user which case she wants to prove first.
    """

    if len(selected_objects) == 0:
        # NB: user_input[1] contains the needed property
        if len(user_input) == 1:
            raise MissingParametersError(
                 InputType.Text,
                 title=_("cases"),
                 output=_("Enter the property you want to discriminate on:")
                                        )
        else:
            h0 = user_input[1]
            h1 = get_new_hyp(proof_step)
            h2 = get_new_hyp(proof_step)
            code = CodeForLean.from_string(f"cases (classical.em ({h0})) "
                                           f"with {h1} {h2}")
            code.add_success_msg(_("Proof by cases"))
            code.add_disjunction(h0, h1, h2)  # Strings, not MathObject
    else:
        prop = selected_objects[0]
        if not prop.is_or():
            error = _("Selected property is not a disjunction")
            raise WrongUserInput(error)
        else:
            code = apply_or(proof_step, selected_objects, user_input)

    return code
示例#20
0
def construct_exists_on_hyp(proof_step,
                            selected_objects: [MathObject]) -> CodeForLean:
    """
    Try to construct an existence property from some object and some property
    Here len(l) = 2
    """

    x = selected_objects[0].info["name"]
    hx = selected_objects[1].info["name"]
    if (not selected_objects[0].math_type.is_prop()) \
            and selected_objects[1].math_type.is_prop():
        new_hypo = get_new_hyp(proof_step)
        code_string = f'have {new_hypo} := exists.intro {x} {hx}'
    elif (not selected_objects[1].math_type.is_prop()) \
            and selected_objects[0].math_type.is_prop():
        x, hx = hx, x
        new_hypo = get_new_hyp(proof_step)
        code_string = f'have {new_hypo} := exists.intro {x} {hx}'
    else:
        error = _("I cannot build an existential property with this")
        raise WrongUserInput(error)
    code = CodeForLean.from_string(code_string)
    code.add_success_msg(_("get new existential property {}").format(new_hypo))
    return code
示例#21
0
def apply_exists(proof_step, selected_object: [MathObject]) -> CodeForLean:
    """
    Apply a property '∃ x, P(x)' to get an x with property P(x).
    """

    selected_hypo = selected_object[0].math_type
    hypo_name = selected_object[0].info["name"]
    x = give_global_name(proof_step=proof_step,
                         math_type=selected_hypo.children[0],
                         hints=[selected_hypo.children[1].to_display()])
    new_hypo_name = get_new_hyp(proof_step)

    if selected_hypo.children[2].node == "PROP_∃":
        code = f'rcases {hypo_name} with ' \
                f'⟨ {x}, ⟨ {new_hypo_name}, {hypo_name} ⟩ ⟩'
    else:
        code = f'cases {hypo_name} with {x} {new_hypo_name}'
    code = CodeForLean.from_string(code)
    if selected_hypo.node == 'QUANT_∃!':
        # We have to add the "simp" tactic to avoid appearance of lambda expr
        code = code.and_then(f'simp at {new_hypo_name}')
    code.add_success_msg(
        _("new object {} with property {}").format(x, new_hypo_name))
    return code
示例#22
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
示例#23
0
def apply_substitute(proof_step, l: [MathObject], user_input: [int], equality):
    """
    Try to rewrite the goal or the first selected property using the last
    selected property.
    """

    goal = proof_step.goal

    codes = CodeForLean.empty_code()
    heq = l[-1]
    left_term = equality.children[0]
    right_term = equality.children[1]
    success1 = ' ' + _("{} replaced by {}").format(left_term.to_display(),
                                             right_term.to_display()) + ' '
    success2 = ' ' + _("{} replaced by {}").format(right_term.to_display(),
                                             left_term.to_display()) + ' '
    choices = [(left_term.to_display(),
                f'Replace by {right_term.to_display()}'),
               (right_term.to_display(),
                f'Replace by {left_term.to_display()}')]
            
    if len(l) == 1:
        # If the user has chosen a direction, apply substitution
        # else if both directions make sense, ask the user for a choice
        # else try direct way or else reverse way.
        h = l[0].info["name"]
        if len(user_input) > 0:
            if user_input[0] == 1:
                success_msg = success2 + _("in target")
                more_code = CodeForLean.from_string(f'rw <- {h}',
                                                    success_msg=success_msg)
            elif user_input[0] == 0:
                success_msg = success1 + _("in target")
                more_code = CodeForLean.from_string(f'rw {h}',
                                                    success_msg=success_msg)
            codes = codes.or_else(more_code)
        else:
            if goal.target.math_type.contains(left_term) and \
                    goal.target.math_type.contains(right_term):
                
                raise MissingParametersError(
                    InputType.Choice,
                    choices, 
                    title=_("Precision of substitution"),
                    output=_("Choose which expression you want to replace"))
            else:
                msg2 = success2 + _("in target")
                more_code2 = CodeForLean.from_string(f'rw <- {h}',
                                                     success_msg=msg2)
                codes = codes.or_else(more_code2)
                msg1 = success1 + _("in target")
                more_code1 = CodeForLean.from_string(f'rw {h}',
                                                     success_msg=msg1)
                codes = codes.or_else(more_code1)

    if len(l) == 2:
        h = l[0].info["name"]
        heq_name = l[-1].info["name"]
        if len(user_input) > 0:
            if user_input[0] == 1:
                success_msg = success2 + _("in {}").format(h)
                more_code = CodeForLean.from_string(f'rw <- {heq_name} at {h}',
                                                    success_msg=success_msg)
                codes = codes.or_else(more_code)

            elif user_input[0] == 0:
                success_msg = success1 + _("in {}").format(h)
                more_code = CodeForLean.from_string(f'rw {heq_name} at {h}',
                                                    success_msg=success_msg)
                codes = codes.or_else(more_code)
        else:
            if l[0].math_type.contains(left_term) and \
                    l[0].math_type.contains(right_term):
                    
                raise MissingParametersError(
                    InputType.Choice,
                    choices, 
                    title=_("Precision of substitution"),
                    output=_("Choose which expression you want to replace"))

        # h, heq_name = heq_name, h
        # codes = codes.or_else(f'rw <- {heq_name} at {h}')
        # codes = codes.or_else(f'rw {heq_name} at {h}')

        msg2 = success2 + _("in {}").format(h)
        more_code2 = CodeForLean.from_string(f'rw <- {heq_name} at {h}',
                                             success_msg=msg2)
        codes = codes.or_else(more_code2)
        msg1 = success1 + _("in {}").format(h)
        more_code1 = CodeForLean.from_string(f'rw {heq_name} at {h}',
                                             success_msg=msg1)
        codes = codes.or_else(more_code1)

    if heq.is_for_all():
        # if property is, e.g. "∀n, u n = c"
        # there is a risk of meta vars if Lean does not know to which n
        # applying the equality
        codes = codes.and_then('no_meta_vars')
    return codes
示例#24
0
def action_new_object(proof_step,
                      selected_objects: [MathObject],
                      user_input: [str] = None,
                      target_selected: bool = True) -> CodeForLean:
    """
    Introduce new object / sub-goal / function
    """

    goal = proof_step.goal

    codes = []
    # Choose between object/sub-goal/function
    if not user_input:
        raise MissingParametersError(InputType.Choice,
                             [(_("Object"), _("Introduce a new object")),
                              (_("Goal"), _("Introduce a new "
                                            "intermediate sub-goal")),
                              (_("Function"), _("Introduce a new "
                                                "function"))],
                             title=_("New object"),
                             output=_("Choose what to introduce:"))
    # Choice = new object
    if user_input[0] == 0:
        if len(user_input) == 1:  # Ask for name
            raise MissingParametersError(InputType.Text,
                                         title="+",
                                         output=_("Name your object:"))
        if len(user_input) == 2:  # Ask for new object
            raise MissingParametersError(InputType.Text,
                                         title="+",
                                         output=_("Introduce a new object")
                                         + "(" + _("e.g.")
                                         + "0, {1}, f(2), ...)")
        else:  # Send code
            name = user_input[1]
            new_hypo_name = get_new_hyp(proof_step)
            new_object = user_input[2]
            codes = CodeForLean.from_string(f"let {name} := {new_object}")
            codes = codes.and_then(f"have {new_hypo_name} : {name} = "
                                                     f"{new_object}")
            codes = codes.and_then("refl")
            codes.add_success_msg(_("New object {} added to the context").
                                  format(name))
            if goal.target.is_for_all():
                # User might want to prove a universal property "∀x..."
                # and mistake "new object" for introduction of the relevant x.
                codes.add_error_msg(_("You might try the ∀ button..."))

    # Choice = new sub-goal
    elif user_input[0] == 1:
        if len(user_input) == 1:
            raise MissingParametersError(InputType.Text,
                                         title="+",
                                         output=_("Introduce new subgoal:"))
        else:
            new_hypo_name = get_new_hyp(proof_step)
            codes = CodeForLean.from_string(f"have {new_hypo_name}:"
                                                     f" ({user_input[1]})")
            codes.add_success_msg(_("New target will be added to the context "
                                    "after being proved"))
            codes.add_subgoal(user_input[1])
    # Choice = new function
    elif user_input[0] == 2:
        return introduce_fun(proof_step, selected_objects)
    return codes
示例#25
0
def method_sorry(proof_step, selected_objects: [MathObject]) -> CodeForLean:
    """
    Close the current sub-goal by sending the 'sorry' code.
    """
    return CodeForLean.from_string('sorry')
示例#26
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)