5

Sometimes <statement> solve_direct (which I usually invoke via <statement> try) lists a number of library theorems and says “The current goal can be solved directly with: …”.

Let <theorem> be one search result of solve_direct, then in most cases I can prove <statement> by (rule theorem).

Sometimes, however, such a proof is not accepted, resulting in the error message “Failed to apply initial proof method”.

Is there a general, different technique for reusing theorems found by solve_direct?

Or does it depend on the individual situation? I could try to work out a minimal example and attach it to this question.

Christoph Lange
  • 595
  • 2
  • 13
  • 1
    Problems might be caused by chained facts, meta-logical connectives in the assumptions, meta-variables (or type variables) in the goal, or maybe other things. I might be able to help make sense of a specific example. – Brian Huffman Aug 29 '13 at 17:10
  • Indeed, I might in future ask for help and post a specific example. However I learnt, from the other replies, about a number of ways that do the job in many practical situations, and that's fine with me for now. – Christoph Lange Sep 02 '13 at 22:16

3 Answers3

5

Personally, I just tend to just use:

apply (metis thm)

which works most of the time without forcing me to think very hard (but will still occasionally fail if tricky resolution is required).

Other methods that will also typically work include:

apply (rule thm)                 (* If "thm" has no premises. *)
apply (erule thm)                (* If "thm" has a single premise. *)
apply (erule thm, assumption+)   (* If "thm" has multiple premises. *)

Why is there no one single answer? The answer is a little complex:

Internally, solve_direct calls find_theorems solves, which then performs the following:

fun etacn thm i = Seq.take (! tac_limit) o etac thm i;
(* ... *)
if Thm.no_prems thm then rtac thm 1 goal
else (etacn thm THEN_ALL_NEW (Goal.norm_hhf_tac THEN' Method.assm_tac ctxt)) 1 goal;

This is the ML code for something similar to rule thm if there are no premises on the rule, or:

apply (erule thm, assumption+)

if there are multiple premises on the rule. As commented by Brian on your question, the above might still fail if there are complex meta-logical connectives in the assumptions (which the norm_hhf_tac deals with, but is not directly exposed as an Isabelle method as far as I am aware).

If you wanted, you could write a new method that exposes the tactic used by find_theorems directly, as follows:

ML {*
  fun solve_direct_tac thm ctxt goal =
  if Thm.no_prems thm then rtac thm 1 goal
  else (etac thm THEN_ALL_NEW (Goal.norm_hhf_tac THEN' Method.assm_tac ctxt)) 1 goal;
*}

method_setup solve =
  {* Attrib.thm >> (fn thm => fn ctxt =>
        SIMPLE_METHOD' (K (solve_direct_tac thm ctxt ))) *}
  "directly solve a rule"

This could then be used as follows:

lemma "⟦ a; b ⟧ ⟹ a ∧ b"
  by (solve conjI)

which should hopefully solve anything solve_direct throws at you.

davidg
  • 5,868
  • 2
  • 33
  • 51
  • Thanks for pointing out how to really do it right. As I was asking from an end user's perspective this approach would be overkill for me. Indeed one of `by (metis thm)`, or sometimes `by metis` (when it turned out that metis didn't need the theorem), or sometimes `by (simp add: thm)` worked for me in the cases I have encountered so far. – Christoph Lange Sep 02 '13 at 22:15
  • 1
    @ChristophLange: I don't tend to know answers to questions such as this, so I look at the source code of Isabelle to work them out; I just wrote out my thought patterns so it didn't seem like my answer came by way of divination. `:)` It is probably worth moving my punchline to the top of the answer, though. – davidg Sep 03 '13 at 00:29
  • Instead of `apply (erule thm, assumption+)` you can also use `apply (erule (1) thm)`, where `1` is the number of additional premises to use. – Joachim Breitner Sep 08 '13 at 21:49
  • @davidg, not that it is good style, but could you extend your method to also do the searching? so that `by (solve_direct)` works always :-) – Joachim Breitner Sep 08 '13 at 21:51
  • @JoachimBreitner: What might be useful is if `solve_direct` output a message along the lines of `try [[by (erule (2) foo)]]`, where clicking the proof inserted it into the buffer (in the same way that Sledgehammer does). Perhaps try requesting on the mailing list? – davidg Sep 09 '13 at 05:25
  • Definitely; I am always surprised that it is not done this way. But maybe it is an obsolete way of interacting anyways. – Joachim Breitner Sep 09 '13 at 07:22
1

I found another way of using solve_direct's suggestions with by rule. When certain very basic rules from the library, such as Hilbert_Choice.someI2, are suggested, it seems that one of the facts in context actually is a rule itself, which may be applicable. The following worked for me at least in two concrete situations (source):

  1. re-examine the “rule-like” fact, the other facts (if any) and the goal
  2. if necessary, reorder the other facts
  3. do the proof using <other_facts> ... by (rule <rule-like-fact>)
Christoph Lange
  • 595
  • 2
  • 13
  • +1 for your changeset on github that is mentioned above. Various proof tools have different strengths, and often it is more informative (also for later proof maintenance) to avoid the heavy hammer, and make the proof more precise. This needs to be well-balanced in practice, neither too much nor too little automated reasoning power. – Makarius Oct 09 '13 at 19:46
0

You can try fact or rule_tac. If I recall correctly, rule sometimes fails to apply a given rule in the presence of other facts and I am not entirely sure why; that question will have to be answered by someone who is more familiar with the implementation details of these methods than I am.

chris
  • 4,988
  • 20
  • 36
Manuel Eberl
  • 7,858
  • 15
  • 24
  • I should have said that I'd like to avoid `apply`-style syntax (which I think is what `rule_tac` implies) if possible. If `fact` means `by (fact thm)` this didn't work in some of my situations. I see from grepping the library that there are lots of ways of parameterising the built-in automated provers with rules (to be seen, e.g., when grepping for `someI2`, which `solve_direct` once suggested to me as a rule), but I am not aware of a good tutorial describing these (e.g. comparable to Tobias Nipkow's “A Tutorial Introduction to Structured Isar Proofs”) – are you? – Christoph Lange Sep 02 '13 at 22:28
  • `rule` requires the chained facts to match the prefix of assumptions of the rule. If you want rule to ignore the chained facts, you need to insert them into the goal first. This can be done with the `-` method, (as in `by - (rule foo)`). – Lars Noschinski Sep 04 '13 at 09:46