action_result assert_cc_action(hypothesis_idx hidx) { if (!get_config().m_cc) return action_result::failed(); congruence_closure & cc = get_cc(); if (has_expr_metavar(curr_state().get_hypothesis_decl(hidx).get_type())) return action_result::failed(); cc.add(hidx); // cc.display(); if (cc.is_inconsistent()) { try { app_builder & b = get_app_builder(); expr false_proof = *cc.get_inconsistency_proof(); trace_action("contradiction by congruence closure"); return action_result(b.mk_false_rec(curr_state().get_target(), false_proof)); } catch (app_builder_exception &) { return action_result::failed(); } } else { expr const & target = curr_state().get_target(); name R; expr lhs, rhs; if (is_relation_app(target, R, lhs, rhs) && cc.is_eqv(R, lhs, rhs)) { expr proof = *cc.get_eqv_proof(R, lhs, rhs); trace_action("equivalence by congruence closure"); return action_result(proof); } else if (is_prop(target) && !is_false(target) && cc.proved(target)) { expr proof = *cc.get_proof(target); trace_action("equivalent to true by congruence closure"); return action_result(proof); } else { return action_result::new_branch(); } } }
virtual action_result resolve(expr const & pr) const override { try { expr it = pr; bool skip = true; for (unsigned i = 0; i < m_num_new_eqs; i++) { if (!is_lambda(it)) { break; skip = false; } it = binding_body(it); } if (skip && closed(it)) { // new eq hypotheses were not used return action_result::solved(it); } state & s = curr_state(); app_builder & b = get_app_builder(); hypothesis const & h = s.get_hypothesis_decl(href_index(m_eq_href)); expr type = h.get_type(); expr lhs, rhs; lean_verify(is_eq(type, lhs, rhs)); name nc_name(m_I_name, "no_confusion"); expr new_pr = mk_app(b.mk_app(nc_name, {m_target, lhs, rhs, m_eq_href}), pr); return action_result::solved(new_pr); } catch (app_builder_exception &) { return action_result::failed(); } }
action_result no_confusion_action(hypothesis_idx hidx) { try { state & s = curr_state(); app_builder & b = get_app_builder(); hypothesis const & h = s.get_hypothesis_decl(hidx); expr type = h.get_type(); expr lhs, rhs; if (!is_eq(type, lhs, rhs)) return action_result::failed(); lhs = whnf(lhs); rhs = whnf(rhs); optional<name> c1 = is_constructor_app(env(), lhs); optional<name> c2 = is_constructor_app(env(), rhs); if (!c1 || !c2) return action_result::failed(); expr A = whnf(infer_type(lhs)); expr I = get_app_fn(A); if (!is_constant(I) || !inductive::is_inductive_decl(env(), const_name(I))) return action_result::failed(); name nct_name(const_name(I), "no_confusion_type"); if (!env().find(nct_name)) return action_result::failed(); expr target = s.get_target(); expr nct = whnf(b.mk_app(nct_name, target, lhs, rhs)); if (c1 == c2) { if (!is_pi(nct)) return action_result::failed(); if (s.has_target_forward_deps(hidx)) { // TODO(Leo): we currently do not handle this case. // To avoid non-termination we remove the given hypothesis, if there // forward dependencies, we would also have to remove them. // Remark: this is a low priority refinement since it will not happen // very often in practice. return action_result::failed(); } unsigned num_params = *inductive::get_num_params(env(), const_name(I)); unsigned cnstr_arity = get_arity(env().get(*c1).get_type()); lean_assert(cnstr_arity >= num_params); unsigned num_new_eqs = cnstr_arity - num_params; s.push_proof_step(new no_confusion_proof_step_cell(const_name(I), target, h.get_self(), num_new_eqs)); s.set_target(binding_domain(nct)); s.del_hypothesis(hidx); trace_action("no_confusion"); return action_result::new_branch(); } else { name nc_name(const_name(I), "no_confusion"); expr pr = b.mk_app(nc_name, {target, lhs, rhs, h.get_self()}); trace_action("no_confusion"); return action_result::solved(pr); } } catch (app_builder_exception &) { return action_result::failed(); } }
action_result by_contradiction_action() { state & s = curr_state(); expr target = whnf(s.get_target()); if (!is_prop(target)) return action_result::failed(); if (blast::is_false(target)) return action_result::failed(); expr not_target; if (is_not(target, not_target)) { s.set_target(mk_arrow(not_target, mk_constant(get_false_name()))); return intros_action(1); } blast_tmp_type_context tmp_tctx; optional<expr> target_decidable = tmp_tctx->mk_class_instance(mk_app(mk_constant(get_decidable_name()), target)); if (!target_decidable) return action_result::failed(); expr href = s.mk_hypothesis(get_app_builder().mk_not(target)); auto pcell = new by_contradiction_proof_step_cell(href); s.push_proof_step(pcell); s.set_target(mk_constant(get_false_name())); trace_action("by_contradiction"); return action_result::new_branch(); }
result simplifier::finalize(result const & r) { if (r.has_proof()) return r; expr pf = get_app_builder().mk_refl(m_rel, r.get_new()); return result(r.get_new(), pf); }